-
Notifications
You must be signed in to change notification settings - Fork 453
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DPDK backend: Add support for meter and counter extern #2813
Changes from 1 commit
a805208
611261b
9c8e6d2
b184e0b
c03e07d
c99d261
c6a5c12
4817ea2
bfb6f02
f5cfb35
5ca47b1
f0c7f9c
f3ab6ad
778cd74
2b992a4
61567fd
009fd24
afa8764
05a68ba
d43963c
8b9927f
3bde5de
f7cb04d
a3e6ef6
6b963ce
8cf5882
00ce76f
32d2abe
7986213
9648cce
d663dbb
76a0557
402ae06
0013778
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -446,32 +446,95 @@ class ConvertInternetChecksum : public PassManager { | |
* for emitting to the .spec file later */ | ||
class CollectRegisterDeclaration : public Inspector { | ||
std::map<const IR::Declaration_Instance *, cstring> *reg_map; | ||
|
||
P4::TypeMap *typeMap; | ||
|
||
public: | ||
CollectRegisterDeclaration( | ||
std::map<const IR::Declaration_Instance *, cstring> *reg_map, P4::TypeMap *) | ||
: reg_map(reg_map) {} | ||
std::map<const IR::Declaration_Instance *, cstring> *reg_map, P4::TypeMap *typeMap) | ||
: reg_map(reg_map), typeMap(typeMap) {} | ||
|
||
bool preorder(const IR::Declaration_Instance *d) override { | ||
if (d->type->is<IR::Type_Specialized>()) { | ||
auto type = d->type->to<IR::Type_Specialized>(); | ||
auto externTypeName = type->baseType->path->name.name; | ||
if (externTypeName == "Register"){ | ||
if (d->arguments->size() != 1 and d->arguments->size() != 2 ) { | ||
::error("%1%: expected size and optionally init_val as arguments", d); | ||
} | ||
reg_map->emplace(d, d->name); | ||
if (d->arguments->size() != 1 and d->arguments->size() != 2 ) { | ||
::error("%1%: expected size and optionally init_val as arguments", d); | ||
} | ||
reg_map->emplace(d, d->name); | ||
} | ||
} | ||
return false; | ||
} | ||
}; | ||
|
||
/* This pass collects PSA meter declaration instances and push them to a map | ||
* for emitting to the .spec file later */ | ||
class CollectMeterDeclaration : public Inspector { | ||
std::map<const IR::Declaration_Instance *, cstring> *met_map; | ||
P4::TypeMap *typeMap; | ||
|
||
public: | ||
CollectMeterDeclaration( | ||
std::map<const IR::Declaration_Instance *, cstring> *met_map, P4::TypeMap *typeMap) | ||
: met_map(met_map) , typeMap(typeMap) {} | ||
|
||
bool preorder(const IR::Declaration_Instance *d) override { | ||
if (d->type->is<IR::Type_Specialized>()) { | ||
auto type = d->type->to<IR::Type_Specialized>(); | ||
auto externTypeName = type->baseType->path->name.name; | ||
if (externTypeName == "Meter"){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no space after ( |
||
if (d->arguments->size() != 2) { | ||
::error("%1%: expected number of meters and type of meter as arguments", d); | ||
} else { | ||
if (d->arguments->at(1) == 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you really want to compare with 0? Not with IR::Constant(0)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps you want to add a test for this case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am facing an issue w.r.t adding a test for this case. I added a test in testdata/p4_16_samples/ for emitting this warning and added the warning in reference stderr output "psa-example-dpdk-meter1.p4-stderr". This test compiles as expected and produces a warning when compiled with p4c-dpdk. However, make check fails while compiling this test using p4test. It fails because of output mismatch as there is no warning when compiling with p4test and reference stderr output has warning. What should I do in this case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So far the p4 reference outputs have always been produced by p4test. |
||
::warning(ErrorType::WARN_UNSUPPORTED, | ||
"%1%: Packet metering is not supported." \ | ||
" Falling back to byte metering.", d); | ||
met_map->emplace(d, d->name); | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
}; | ||
|
||
class AddRegisterDeclaration : public PassManager { | ||
/* This pass collects PSA counter declaration instances and push them to a map | ||
* for emitting to the .spec file later */ | ||
class CollectCounterDeclaration : public Inspector { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't you do both of them in a single traversal? There is a lot of common code. |
||
std::map<const IR::Declaration_Instance *, cstring> *cnt_map; | ||
P4::TypeMap *typeMap; | ||
|
||
public: | ||
CollectCounterDeclaration( | ||
std::map<const IR::Declaration_Instance *, cstring> *cnt_map, P4::TypeMap *typeMap) | ||
: cnt_map(cnt_map) , typeMap(typeMap) {} | ||
|
||
bool preorder(const IR::Declaration_Instance *d) override { | ||
if (d->type->is<IR::Type_Specialized>()) { | ||
auto type = d->type->to<IR::Type_Specialized>(); | ||
auto externTypeName = type->baseType->path->name.name; | ||
if (externTypeName == "Counter"){ | ||
if (d->arguments->size() != 2 ) { | ||
::error("%1%: expected n_counters and counter type as arguments", d); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this error message does not seem very clear to me. |
||
} | ||
cnt_map->emplace(d, d->name); | ||
} | ||
} | ||
return false; | ||
} | ||
}; | ||
|
||
/* This passmanager is for collecting the extern declarations for register meter and counter */ | ||
class AddExternDeclaration : public PassManager { | ||
public: | ||
std::map<const IR::Declaration_Instance *, cstring> reg_map; | ||
AddRegisterDeclaration(P4::TypeMap *typeMap) { | ||
std::map<const IR::Declaration_Instance *, cstring> cnt_map; | ||
std::map<const IR::Declaration_Instance *, cstring> met_map; | ||
AddExternDeclaration(P4::TypeMap *typeMap) { | ||
passes.push_back(new CollectRegisterDeclaration(®_map, typeMap)); | ||
passes.push_back(new CollectCounterDeclaration(&cnt_map, typeMap)); | ||
passes.push_back(new CollectMeterDeclaration(&met_map, typeMap)); | ||
} | ||
}; | ||
|
||
|
@@ -584,6 +647,8 @@ class RewriteToDpdkArch : public PassManager { | |
*args_struct_map; | ||
std::map<const IR::Declaration_Instance *, cstring> *csum_map; | ||
std::map<const IR::Declaration_Instance *, cstring> *reg_map; | ||
std::map<const IR::Declaration_Instance *, cstring> *cnt_map; | ||
std::map<const IR::Declaration_Instance *, cstring> *met_map; | ||
RewriteToDpdkArch(P4::ReferenceMap *refMap, P4::TypeMap *typeMap, | ||
DpdkVariableCollector *collector) { | ||
setName("RewriteToDpdkArch"); | ||
|
@@ -631,9 +696,11 @@ class RewriteToDpdkArch : public PassManager { | |
args_struct_map = &p->args_struct_map; | ||
passes.push_back(p); | ||
passes.push_back(new ConvertLogicalExpression); | ||
auto insertRegDeclaration = new AddRegisterDeclaration(typeMap); | ||
passes.push_back(insertRegDeclaration); | ||
reg_map = &insertRegDeclaration->reg_map; | ||
auto insertExternDeclaration = new AddExternDeclaration(typeMap); | ||
passes.push_back(insertExternDeclaration); | ||
reg_map = &insertExternDeclaration->reg_map; | ||
cnt_map = &insertExternDeclaration->cnt_map; | ||
met_map = &insertExternDeclaration->met_map; | ||
} | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,6 +73,27 @@ bool ConvertStatementToDpdk::preorder(const IR::AssignmentStatement *a) { | |
i = new IR::DpdkGetChecksumStatement( | ||
left, e->object->getName(), intermediate); | ||
} | ||
} else if (e->originalExternType->getName().name == "Meter") { | ||
if (e->method->getName().name == "execute") { | ||
auto argSize = e->expr->arguments->size(); | ||
|
||
// DPDK target needs index and packet length as mandatory parameters | ||
if (argSize < 2) | ||
::error(ErrorType::ERR_UNEXPECTED, "Expected atleast 2 arguments for %1%", | ||
e->object->getName()); | ||
mihaibudiu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const IR::Expression *color_in = nullptr; | ||
const IR::Expression *length = nullptr; | ||
auto index = (*e->expr->arguments)[0]->expression; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think using arguments->at(0) is safer. |
||
if (argSize == 2) { | ||
length = (*e->expr->arguments)[1]->expression; | ||
color_in = new IR::Constant(1); | ||
} else if (argSize == 3) { | ||
length = (*e->expr->arguments)[2]->expression; | ||
color_in = (*e->expr->arguments)[1]->expression; | ||
} | ||
i = new IR::DpdkMeterExecuteStatement( | ||
e->object->getName(), index, length, color_in, left); | ||
} | ||
} else if (e->originalExternType->getName().name == "Register") { | ||
if (e->method->getName().name == "read") { | ||
auto index = (*e->expr->arguments)[0]->expression; | ||
|
@@ -402,21 +423,46 @@ bool ConvertStatementToDpdk::preorder(const IR::MethodCallStatement *s) { | |
} | ||
} else if (a->originalExternType->getName().name == "Meter") { | ||
if (a->method->getName().name == "execute") { | ||
auto args = a->expr->arguments; | ||
auto index = args->at(0)->expression; | ||
auto color = args->at(1)->expression; | ||
auto meter = a->object->getName(); | ||
add_instr( | ||
new IR::DpdkMeterExecuteStatement(meter, index, color)); | ||
// DPDK target requires the result of meter execute method is assigned to a | ||
// variable of PSA_MeterColor_t type. | ||
::error(ErrorType::ERR_UNSUPPORTED, "LHS of meter execute statement is missing " \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no return here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so, there is already a return just after the if-else chain. |
||
"Use this format instead : color_out = %1%.execute(index, color_in)", | ||
a->object->getName()); | ||
} else { | ||
BUG("Meter function not implemented."); | ||
} | ||
} else if (a->originalExternType->getName().name == "Counter") { | ||
auto di = a->object->to<IR::Declaration_Instance>(); | ||
auto declArgs = di->arguments; | ||
unsigned value = 0; | ||
auto counter_type = declArgs->at(1)->expression; | ||
if (counter_type->is<IR::Constant>()) | ||
value = counter_type->to<IR::Constant>()->asUnsigned(); | ||
if (a->method->getName().name == "count") { | ||
auto args = a->expr->arguments; | ||
auto index = args->at(0)->expression; | ||
auto counter = a->object->getName(); | ||
add_instr(new IR::DpdkCounterCountStatement(counter, index)); | ||
if (args->size() < 1){ | ||
::error(ErrorType::ERR_UNEXPECTED, "Expected atleast 1 arguments for %1%", | ||
a->object->getName()); | ||
} else { | ||
const IR::Expression *incr = nullptr; | ||
auto index = args->at(0)->expression; | ||
auto counter = a->object->getName(); | ||
if (args->size() == 2) | ||
incr = args->at(1)->expression; | ||
if (value == 2) { | ||
if (incr) { | ||
add_instr(new IR::DpdkCounterCountStatement(counter+"_packets", | ||
index, incr)); | ||
add_instr(new IR::DpdkCounterCountStatement(counter+"_bytes", | ||
index)); | ||
} else { | ||
::error(ErrorType::ERR_UNEXPECTED, | ||
"Expected packet length argument for %1%", a->object->getName()); | ||
} | ||
} else { | ||
add_instr(new IR::DpdkCounterCountStatement(counter, index, incr)); | ||
} | ||
} | ||
} else { | ||
BUG("Counter function not implemented"); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -163,10 +163,41 @@ std::ostream &IR::DpdkExternDeclaration::toSpec(std::ostream &out) const { | |
} | ||
} | ||
else if ( DPDK::toStr(this->getType()) == "Counter") { | ||
//TODO yet to be implemented | ||
auto args = this->arguments; | ||
unsigned value = 0; | ||
if (args->size() < 2) { | ||
::error ("Counter extern declaration %1% must contain 2 parameters\n", this->Name()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. your indentation is not consistent with our standard |
||
} else { | ||
auto n_counters = args->at(0)->expression; | ||
auto counter_type = args->at(1)->expression; | ||
if (counter_type->is<IR::Constant>()) | ||
value = counter_type->to<IR::Constant>()->asUnsigned(); | ||
if (value == 2) { | ||
/* For PACKETS_AND_BYTES counter type, two regarray declarations are emitted and | ||
the counter name is suffixed with _packets and _bytes */ | ||
auto regDecl = new IR::DpdkRegisterDeclStatement(this->Name()+"_packets", n_counters, | ||
new IR::Constant(0)); | ||
regDecl->toSpec(out) << std::endl << std::endl; | ||
regDecl = new IR::DpdkRegisterDeclStatement(this->Name()+"_bytes", n_counters, | ||
new IR::Constant(0)); | ||
regDecl->toSpec(out) << std::endl; | ||
} else { | ||
auto regDecl = new IR::DpdkRegisterDeclStatement(this->Name(), n_counters, | ||
new IR::Constant(0)); | ||
regDecl->toSpec(out) << std::endl; | ||
} | ||
} | ||
} | ||
else if ( DPDK::toStr(this->getType()) == "Meter") { | ||
//TODO yet to be implemented | ||
auto args = this->arguments; | ||
if (args->size() < 2) { | ||
::error ("Meter extern declaration %1% must contain a size parameter \ | ||
and meter type parameter", this->Name()); | ||
} else { | ||
auto n_meters = args->at(0)->expression; | ||
auto metDecl = new IR::DpdkMeterDeclStatement(this->Name(), n_meters); | ||
metDecl->toSpec(out) << std::endl; | ||
} | ||
} | ||
return out; | ||
} | ||
|
@@ -392,7 +423,9 @@ std::ostream &IR::DpdkAction::toSpec(std::ostream &out) const { | |
out << "{" << std::endl; | ||
for (auto i : statements) { | ||
out << "\t"; | ||
i->toSpec(out) << std::endl; | ||
i->toSpec(out); | ||
if (!i->to<IR::DpdkLabelStatement>()) | ||
out << std::endl; | ||
} | ||
out << "\treturn" << std::endl; | ||
out << "}"; | ||
|
@@ -449,14 +482,26 @@ std::ostream &IR::DpdkVerifyStatement::toSpec(std::ostream &out) const { | |
return out; | ||
} | ||
|
||
std::ostream &IR::DpdkMeterDeclStatement::toSpec(std::ostream &out) const { | ||
out << "metarray " << meter << " size " << DPDK::toStr(size); | ||
return out; | ||
} | ||
|
||
std::ostream &IR::DpdkMeterExecuteStatement::toSpec(std::ostream &out) const { | ||
out << "meter_execute " << meter << " " << DPDK::toStr(index) << " " | ||
<< DPDK::toStr(color); | ||
out << "meter " << meter << " " << DPDK::toStr(index) << " " << DPDK::toStr(length); | ||
out << " " << DPDK::toStr(color_in) << " " << DPDK::toStr(color_out); | ||
return out; | ||
} | ||
|
||
/* DPDK target uses Registers for implementing using Counters, atomic register add instruction | ||
is used for incrementing the counter. Packet counters are incremented by packet length | ||
specified as parameter and byte counters are incremente by 1 */ | ||
std::ostream &IR::DpdkCounterCountStatement::toSpec(std::ostream &out) const { | ||
out << "counter_count " << counter << " " << DPDK::toStr(index); | ||
out << "regadd " << counter << " " << DPDK::toStr(index) << " "; | ||
if (incr) | ||
out << DPDK::toStr(incr); | ||
else | ||
out << "1"; | ||
return out; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these can be combined into a single line