diff --git a/src/sst/elements/miranda/generators/copygen.h b/src/sst/elements/miranda/generators/copygen.h index 1a617a8585..4e20c9300b 100644 --- a/src/sst/elements/miranda/generators/copygen.h +++ b/src/sst/elements/miranda/generators/copygen.h @@ -28,77 +28,92 @@ namespace Miranda { class CopyGenerator : public RequestGenerator { public: + SST_ELI_REGISTER_SUBCOMPONENT( + CopyGenerator, + "miranda", + "CopyGenerator", + SST_ELI_ELEMENT_VERSION(1,0,0), + "Creates a single copy of stream of reads/writes replicating an array copy pattern", + SST::Miranda::RequestGenerator + ) + + SST_ELI_DOCUMENT_PARAMS( + { "read_start_address", "Sets the start read address for this generator", "0" }, + { "write_start_address", "Sets the start target address for writes for the generator", "1024" }, + { "request_size", "Sets the size of each request in bytes", "8" }, + { "request_count", "Sets the number of items to be copied", "128" }, + { "verbose", "Sets the verbosity of the output", "0" } + ) + CopyGenerator( ComponentId_t id, Params& params) : RequestGenerator(id, params) { build(params); } + CopyGenerator() = default; + void build(Params& params) { const uint32_t verbose = params.find("verbose", 0); - out = new Output("CopyGenerator[@p:@l]: ", verbose, 0, Output::STDOUT); + out = new Output("CopyGenerator[@p:@l]: ", verbose, 0, Output::STDOUT); - readAddr = params.find("read_start_address", 0); - reqLength = params.find("operandwidth", 8); - itemCount = params.find("request_count", 1024); + readAddr = params.find("read_start_address", 0); + reqLength = params.find("operandwidth", 8); + itemCount = params.find("request_count", 1024); - n_per_call = params.find("n_per_call", 2); + n_per_call = params.find("n_per_call", 2); - // Write address default is sized for number of requests * req lengtgh - writeAddr = params.find("write_start_address", - readAddr + (reqLength * itemCount)); + // Write address default is sized for number of requests * req lengtgh + writeAddr = params.find("write_start_address", + readAddr + (reqLength * itemCount)); - // Start generator at 0 - nextItem = 0; + // Start generator at 0 + nextItem = 0; - out->verbose(CALL_INFO, 1, 0, "Copy count is %" PRIu64 "\n", itemCount); - out->verbose(CALL_INFO, 1, 0, "operandwidth %" PRIu64 "\n", reqLength); - out->verbose(CALL_INFO, 1, 0, "read start 0x%" PRIx64 "\n", readAddr); - out->verbose(CALL_INFO, 1, 0, "writestart 0x%" PRIx64 "\n", writeAddr); - out->verbose(CALL_INFO, 1, 0, "N-per-generate %" PRIu64 "\n", n_per_call); + out->verbose(CALL_INFO, 1, 0, "Copy count is %" PRIu64 "\n", itemCount); + out->verbose(CALL_INFO, 1, 0, "operandwidth %" PRIu64 "\n", reqLength); + out->verbose(CALL_INFO, 1, 0, "read start 0x%" PRIx64 "\n", readAddr); + out->verbose(CALL_INFO, 1, 0, "writestart 0x%" PRIx64 "\n", writeAddr); + out->verbose(CALL_INFO, 1, 0, "N-per-generate %" PRIu64 "\n", n_per_call); } ~CopyGenerator() { - delete out; + delete out; } void generate(MirandaRequestQueue* q) { - for ( int i = 0; i < n_per_call; i++ ) { - if(nextItem == itemCount) { - return; - } - - MemoryOpRequest* read = new MemoryOpRequest(readAddr + (nextItem * reqLength), reqLength, READ); - MemoryOpRequest* write = new MemoryOpRequest(writeAddr + (nextItem * reqLength), reqLength, WRITE); - write->addDependency(read->getRequestID()); - q->push_back(read); - q->push_back(write); - - nextItem++; + for ( int i = 0; i < n_per_call; i++ ) { + if(nextItem == itemCount) { + return; + } + + MemoryOpRequest* read = new MemoryOpRequest(readAddr + (nextItem * reqLength), reqLength, READ); + MemoryOpRequest* write = new MemoryOpRequest(writeAddr + (nextItem * reqLength), reqLength, WRITE); + write->addDependency(read->getRequestID()); + q->push_back(read); + q->push_back(write); + + nextItem++; } } bool isFinished() { - return (nextItem == itemCount); + return (nextItem == itemCount); } void completed() {} - SST_ELI_REGISTER_SUBCOMPONENT( - CopyGenerator, - "miranda", - "CopyGenerator", - SST_ELI_ELEMENT_VERSION(1,0,0), - "Creates a single copy of stream of reads/writes replicating an array copy pattern", - SST::Miranda::RequestGenerator - ) + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::RequestGenerator::serialize_order(ser); + SST_SER(nextItem); + SST_SER(readAddr); + SST_SER(writeAddr); + SST_SER(itemCount); + SST_SER(reqLength); + SST_SER(n_per_call); + SST_SER(out); + } - SST_ELI_DOCUMENT_PARAMS( - { "read_start_address", "Sets the start read address for this generator", "0" }, - { "write_start_address", "Sets the start target address for writes for the generator", "1024" }, - { "request_size", "Sets the size of each request in bytes", "8" }, - { "request_count", "Sets the number of items to be copied", "128" }, - { "verbose", "Sets the verbosity of the output", "0" } - ) + ImplementSerializable(SST::Miranda::CopyGenerator) private: uint64_t nextItem; @@ -108,7 +123,6 @@ class CopyGenerator : public RequestGenerator { uint64_t reqLength; uint64_t n_per_call; Output* out; - }; } diff --git a/src/sst/elements/miranda/generators/gupsgen.h b/src/sst/elements/miranda/generators/gupsgen.h index 73e87c522d..a225b46d40 100644 --- a/src/sst/elements/miranda/generators/gupsgen.h +++ b/src/sst/elements/miranda/generators/gupsgen.h @@ -31,13 +31,6 @@ namespace Miranda { class GUPSGenerator : public RequestGenerator { public: - GUPSGenerator( ComponentId_t id, Params& params ); - void build(Params ¶ms); - ~GUPSGenerator(); - void generate(MirandaRequestQueue* q); - bool isFinished(); - void completed(); - SST_ELI_REGISTER_SUBCOMPONENT( GUPSGenerator, "miranda", @@ -58,9 +51,32 @@ class GUPSGenerator : public RequestGenerator { { "issue_op_fences", "Issue operation fences, \"yes\" or \"no\", default is yes", "yes" } ) + GUPSGenerator( ComponentId_t id, Params& params ); + GUPSGenerator() = default; + ~GUPSGenerator(); + void build(Params ¶ms); + void generate(MirandaRequestQueue* q); + bool isFinished(); + void completed(); + + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::RequestGenerator::serialize_order(ser); + SST_SER(reqLength); + SST_SER(memLength); + SST_SER(memStart); + SST_SER(issueCount); + SST_SER(iterations); + SST_SER(seed_a); + SST_SER(seed_b); + SST_SER(rng); + SST_SER(out); + SST_SER(issueOpFences); + } + + ImplementSerializable(SST::Miranda::GUPSGenerator) + private: uint64_t reqLength; - uint64_t memLength; uint64_t memStart; uint64_t issueCount; @@ -70,7 +86,6 @@ class GUPSGenerator : public RequestGenerator { Random* rng; Output* out; bool issueOpFences; - }; } diff --git a/src/sst/elements/miranda/generators/inorderstreambench.h b/src/sst/elements/miranda/generators/inorderstreambench.h index b2201172e9..9430f6f013 100644 --- a/src/sst/elements/miranda/generators/inorderstreambench.h +++ b/src/sst/elements/miranda/generators/inorderstreambench.h @@ -28,8 +28,29 @@ namespace Miranda { class InOrderSTREAMBenchGenerator : public RequestGenerator { public: + SST_ELI_REGISTER_SUBCOMPONENT( + InOrderSTREAMBenchGenerator, + "miranda", + "InOrderSTREAMBenchGenerator", + SST_ELI_ELEMENT_VERSION(1,0,0), + "Creates a representation of the STREAM benchmark for in-order CPUs", + SST::Miranda::RequestGenerator + ) + + SST_ELI_DOCUMENT_PARAMS( + { "verbose", "Sets the verbosity output of the generator", "0" }, + { "n", "Sets the number of elements in the STREAM arrays", "10000" }, + { "block_per_call", "Sets the number of iterations to generate per call to the generation function", "1"}, + { "operandwidth", "Sets the length of the request, default=8 (i.e. one double)", "8" }, + { "start_a", "Sets the start address of the array a", "0" }, + { "start_b", "Sets the start address of the array b", "1024" }, + { "start_c", "Sets the start address of the array c", "2048" }, + ) + InOrderSTREAMBenchGenerator( ComponentId_t id, Params& params ) : RequestGenerator(id, params) { build(params); } + InOrderSTREAMBenchGenerator() = default; + void build(Params& params) { const uint32_t verbose = params.find("verbose", 0); @@ -94,24 +115,24 @@ class InOrderSTREAMBenchGenerator : public RequestGenerator { void completed() {} - SST_ELI_REGISTER_SUBCOMPONENT( - InOrderSTREAMBenchGenerator, - "miranda", - "InOrderSTREAMBenchGenerator", - SST_ELI_ELEMENT_VERSION(1,0,0), - "Creates a representation of the STREAM benchmark for in-order CPUs", - SST::Miranda::RequestGenerator - ) + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::RequestGenerator::serialize_order(ser); + SST_SER(requestLen); + + SST_SER(start_a); + SST_SER(start_b); + SST_SER(start_c); + + SST_SER(n); + SST_SER(block_per_call); + SST_SER(i); + + SST_SER(out); + } + + ImplementSerializable(SST::Miranda::InOrderSTREAMBenchGenerator) + - SST_ELI_DOCUMENT_PARAMS( - { "verbose", "Sets the verbosity output of the generator", "0" }, - { "n", "Sets the number of elements in the STREAM arrays", "10000" }, - { "block_per_call", "Sets the number of iterations to generate per call to the generation function", "1"}, - { "operandwidth", "Sets the length of the request, default=8 (i.e. one double)", "8" }, - { "start_a", "Sets the start address of the array a", "0" }, - { "start_b", "Sets the start address of the array b", "1024" }, - { "start_c", "Sets the start address of the array c", "2048" }, - ) private: uint64_t requestLen; diff --git a/src/sst/elements/miranda/generators/nullgen.h b/src/sst/elements/miranda/generators/nullgen.h index ef254b1d0b..429796aeeb 100644 --- a/src/sst/elements/miranda/generators/nullgen.h +++ b/src/sst/elements/miranda/generators/nullgen.h @@ -30,12 +30,6 @@ namespace Miranda { class EmptyGenerator : public RequestGenerator { public: - EmptyGenerator( ComponentId_t id, Params& params ) : RequestGenerator(id, params) {} - ~EmptyGenerator() { } - void generate(MirandaRequestQueue* q) { } - bool isFinished() { return true; } - void completed() { } - SST_ELI_REGISTER_SUBCOMPONENT( EmptyGenerator, "miranda", @@ -48,6 +42,20 @@ class EmptyGenerator : public RequestGenerator { SST_ELI_DOCUMENT_PARAMS( ) + EmptyGenerator( ComponentId_t id, Params& params ) : RequestGenerator(id, params) {} + EmptyGenerator() = default; + ~EmptyGenerator() { } + void generate(MirandaRequestQueue* q) { } + bool isFinished() { return true; } + void completed() { } + + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::RequestGenerator::serialize_order(ser); + } + + ImplementSerializable(SST::Miranda::EmptyGenerator) + + }; } diff --git a/src/sst/elements/miranda/generators/randomgen.h b/src/sst/elements/miranda/generators/randomgen.h index cc0ef4df94..280acc52a2 100644 --- a/src/sst/elements/miranda/generators/randomgen.h +++ b/src/sst/elements/miranda/generators/randomgen.h @@ -31,13 +31,6 @@ namespace Miranda { class RandomGenerator : public RequestGenerator { public: - RandomGenerator( ComponentId_t id, Params& params ); - void build(Params& params); - ~RandomGenerator(); - void generate(MirandaRequestQueue* q); - bool isFinished(); - void completed(); - SST_ELI_REGISTER_SUBCOMPONENT( RandomGenerator, "miranda", @@ -54,6 +47,27 @@ class RandomGenerator : public RequestGenerator { { "max_address", "Maximum address allowed for generation", "16384" }, { "issue_op_fences", "Issue operation fences, \"yes\" or \"no\", default is yes", "yes" } ) + + RandomGenerator( ComponentId_t id, Params& params ); + RandomGenerator() = default; + ~RandomGenerator(); + void build(Params& params); + void generate(MirandaRequestQueue* q); + bool isFinished(); + void completed(); + + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::RequestGenerator::serialize_order(ser); + SST_SER(reqLength); + SST_SER(maxAddr); + SST_SER(issueCount); + SST_SER(issueOpFences); + SST_SER(rng); + SST_SER(out); + } + + ImplementSerializable(SST::Miranda::RandomGenerator) + private: uint64_t reqLength; uint64_t maxAddr; diff --git a/src/sst/elements/miranda/generators/revsinglestream.h b/src/sst/elements/miranda/generators/revsinglestream.h index e445431a1e..90f6dc8298 100644 --- a/src/sst/elements/miranda/generators/revsinglestream.h +++ b/src/sst/elements/miranda/generators/revsinglestream.h @@ -28,13 +28,6 @@ namespace Miranda { class ReverseSingleStreamGenerator : public RequestGenerator { public: - ReverseSingleStreamGenerator( ComponentId_t id, Params& params ); - void build(Params& params); - ~ReverseSingleStreamGenerator(); - void generate(MirandaRequestQueue* q); - bool isFinished(); - void completed(); - SST_ELI_REGISTER_SUBCOMPONENT( ReverseSingleStreamGenerator, "miranda", @@ -52,6 +45,29 @@ class ReverseSingleStreamGenerator : public RequestGenerator { { "stride", "Sets the stride, since this is a reverse stream this is subtracted per iteration, def=1", "1" }, ) + ReverseSingleStreamGenerator( ComponentId_t id, Params& params ); + ReverseSingleStreamGenerator() = default; + ~ReverseSingleStreamGenerator(); + void build(Params& params); + void generate(MirandaRequestQueue* q); + bool isFinished(); + void completed(); + + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::RequestGenerator::serialize_order(ser); + SST_SER(startIndex); + SST_SER(stopIndex); + SST_SER(datawidth); + SST_SER(nextIndex); + SST_SER(stride); + + SST_SER(out); + } + + ImplementSerializable(SST::Miranda::ReverseSingleStreamGenerator) + + + private: uint64_t startIndex; uint64_t stopIndex; diff --git a/src/sst/elements/miranda/generators/singlestream.h b/src/sst/elements/miranda/generators/singlestream.h index 193946ef7b..eea15a547c 100644 --- a/src/sst/elements/miranda/generators/singlestream.h +++ b/src/sst/elements/miranda/generators/singlestream.h @@ -28,13 +28,6 @@ namespace Miranda { class SingleStreamGenerator : public RequestGenerator { public: - SingleStreamGenerator( ComponentId_t id, Params& params ); - void build(Params& params); - ~SingleStreamGenerator(); - void generate(MirandaRequestQueue* q); - bool isFinished(); - void completed(); - SST_ELI_REGISTER_SUBCOMPONENT( SingleStreamGenerator, "miranda", @@ -53,6 +46,29 @@ class SingleStreamGenerator : public RequestGenerator { { "memOp", "All reqeusts will be of this type, [Read/Write]", "Read" }, ) + SingleStreamGenerator( ComponentId_t id, Params& params ); + SingleStreamGenerator() = default; + ~SingleStreamGenerator(); + void build(Params& params); + void generate(MirandaRequestQueue* q); + bool isFinished(); + void completed(); + + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::RequestGenerator::serialize_order(ser); + SST_SER(reqLength); + SST_SER(maxAddr); + SST_SER(issueCount); + SST_SER(nextAddr); + SST_SER(startAddr); + + SST_SER(out); + SST_SER(memOp); + } + + ImplementSerializable(SST::Miranda::SingleStreamGenerator) + + private: uint64_t reqLength; uint64_t maxAddr; diff --git a/src/sst/elements/miranda/generators/spmvgen.h b/src/sst/elements/miranda/generators/spmvgen.h index 9769bcaad2..8f56de742b 100644 --- a/src/sst/elements/miranda/generators/spmvgen.h +++ b/src/sst/elements/miranda/generators/spmvgen.h @@ -30,8 +30,33 @@ namespace Miranda { class SPMVGenerator : public RequestGenerator { public: + SST_ELI_REGISTER_SUBCOMPONENT( + SPMVGenerator, + "miranda", + "SPMVGenerator", + SST_ELI_ELEMENT_VERSION(1,0,0), + "Creates a diagonal matrix access pattern", + SST::Miranda::RequestGenerator + ) + + SST_ELI_DOCUMENT_PARAMS( + { "matrix_nx", "Sets the horizontal dimension of the matrix", "10" }, + { "matrix_ny", "Sets the vertical dimension of the matrix (the number of rows)", "10" }, + { "element_width", "Sets the width of one matrix element, typically 8 for a double", "8" }, + { "lhs_start_addr", "Sets the start address of the LHS vector", "0" }, + { "rhs_start_addr", "Sets the start address of the RHS vector", "80" }, + { "local_row_start", "Sets the row at which this generator will start processing", "0" }, + { "local_row_end", "Sets the end at which rows will be processed by this generator", "10" }, + { "ordinal_width", "Sets the width of ordinals (indices) in the matrix, typically 4 or 8", "8"}, + { "matrix_row_indices_start_addr", "Sets the row indices start address for the matrix", "0" }, + { "matrix_col_indices_start_addr", "Sets the col indices start address for the matrix", "0" }, + { "matrix_element_start_addr", "Sets the start address of the elements array", "0" }, + { "iterations", "Sets the number of repeats to perform" }, + { "matrix_nnz_per_row", "Sets the number of non-zero elements per row", "9" } + ) SPMVGenerator( ComponentId_t id, Params& params ) : RequestGenerator(id, params) { build(params); } + SPMVGenerator() = default; void build(Params& params) { const uint32_t verbose = params.find("verbose", 0); @@ -44,11 +69,11 @@ class SPMVGenerator : public RequestGenerator { uint64_t nextStartAddr = 0; - // LHS vector has Nx elements of size elementWidth + // LHS vector has Nx elements of size elementWidth lhsVecStartAddr = params.find("lhs_start_addr", nextStartAddr); nextStartAddr += matrixNx * elementWidth; - // RHS vector has Ny elements of size elementWidth + // RHS vector has Ny elements of size elementWidth rhsVecStartAddr = params.find("rhs_start_addr", nextStartAddr); nextStartAddr += matrixNy * elementWidth; @@ -58,15 +83,15 @@ class SPMVGenerator : public RequestGenerator { ordinalWidth = params.find("ordinal_width", 8); matrixNNZPerRow = params.find("matrix_nnz_per_row", 4); - // Row-index vector has Ny+1 elements of size ordinalWidth + // Row-index vector has Ny+1 elements of size ordinalWidth matrixRowIndicesStartAddr = params.find("matrix_row_indices_start_addr", nextStartAddr); nextStartAddr += (ordinalWidth * (matrixNy + 1)); - // Col-index vector has Ny * NNZ elements of size ordinalWidth + // Col-index vector has Ny * NNZ elements of size ordinalWidth matrixColumnIndicesStartAddr = params.find("matrix_col_indices_start_addr", nextStartAddr); nextStartAddr += (matrixNy * ordinalWidth * matrixNNZPerRow); - // Matrix vector has Ny * NNZ elements of size elementWidth + // Matrix vector has Ny * NNZ elements of size elementWidth matrixElementsStartAddr = params.find("matrix_element_start_addr", nextStartAddr); iterations = params.find("iterations", 1); @@ -80,44 +105,45 @@ class SPMVGenerator : public RequestGenerator { for(uint64_t row = localRowStart; row < localRowEnd; row++) { out->verbose(CALL_INFO, 2, 0, "Generating access for row %" PRIu64 "\n", row); - MemoryOpRequest* readStart = new MemoryOpRequest(matrixRowIndicesStartAddr + (ordinalWidth * row), ordinalWidth, READ); - MemoryOpRequest* readEnd = new MemoryOpRequest(matrixRowIndicesStartAddr + (ordinalWidth * (row + 1)), ordinalWidth, READ); + MemoryOpRequest* readStart = new MemoryOpRequest(matrixRowIndicesStartAddr + (ordinalWidth * row), ordinalWidth, READ); + MemoryOpRequest* readEnd = new MemoryOpRequest(matrixRowIndicesStartAddr + (ordinalWidth * (row + 1)), ordinalWidth, READ); q->push_back(readStart); q->push_back(readEnd); - MemoryOpRequest* readResultCurrentValue = new MemoryOpRequest(rhsVecStartAddr + - (row * elementWidth), elementWidth, WRITE); - MemoryOpRequest* writeResult = new MemoryOpRequest(rhsVecStartAddr + - (row * elementWidth), elementWidth, WRITE); + MemoryOpRequest* readResultCurrentValue = new MemoryOpRequest(rhsVecStartAddr + + (row * elementWidth), elementWidth, WRITE); + MemoryOpRequest* writeResult = new MemoryOpRequest(rhsVecStartAddr + + (row * elementWidth), elementWidth, WRITE); writeResult->addDependency(readResultCurrentValue->getRequestID()); q->push_back(readResultCurrentValue); - // Putting non-zeros on the diagonal + // Putting non-zeros on the diagonal for(uint64_t j = 0; j < matrixNNZPerRow; j++) { - uint64_t col = j + row; - if (col >= matrixNx) - break; + uint64_t col = j + row; + if (col >= matrixNx) { + break; + } out->verbose(CALL_INFO, 4, 0, "Generating access for row %" PRIu64 ", column: %" PRIu64 "\n", - row, col); + row, col); - MemoryOpRequest* readMatElement = new MemoryOpRequest(matrixElementsStartAddr + - (row * matrixNNZPerRow + j) * elementWidth, elementWidth, READ); - MemoryOpRequest* readCol = new MemoryOpRequest(matrixColumnIndicesStartAddr + - (row * matrixNNZPerRow + j) * ordinalWidth, ordinalWidth, READ); - MemoryOpRequest* readLHSElem = new MemoryOpRequest(lhsVecStartAddr + - col * elementWidth, elementWidth, READ); + MemoryOpRequest* readMatElement = new MemoryOpRequest(matrixElementsStartAddr + + (row * matrixNNZPerRow + j) * elementWidth, elementWidth, READ); + MemoryOpRequest* readCol = new MemoryOpRequest(matrixColumnIndicesStartAddr + + (row * matrixNNZPerRow + j) * ordinalWidth, ordinalWidth, READ); + MemoryOpRequest* readLHSElem = new MemoryOpRequest(lhsVecStartAddr + + col * elementWidth, elementWidth, READ); readCol->addDependency(readStart->getRequestID()); readCol->addDependency(readEnd->getRequestID()); - readMatElement->addDependency(readStart->getRequestID()); - readMatElement->addDependency(readEnd->getRequestID()); + readMatElement->addDependency(readStart->getRequestID()); + readMatElement->addDependency(readEnd->getRequestID()); readLHSElem->addDependency(readCol->getRequestID()); - writeResult->addDependency(readLHSElem->getRequestID()); + writeResult->addDependency(readLHSElem->getRequestID()); writeResult->addDependency(readMatElement->getRequestID()); q->push_back(readCol); @@ -137,33 +163,29 @@ class SPMVGenerator : public RequestGenerator { void completed() {} - SST_ELI_REGISTER_SUBCOMPONENT( - SPMVGenerator, - "miranda", - "SPMVGenerator", - SST_ELI_ELEMENT_VERSION(1,0,0), - "Creates a diagonal matrix access pattern", - SST::Miranda::RequestGenerator - ) + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::RequestGenerator::serialize_order(ser); + SST_SER(iterations); + SST_SER(matrixNx); + SST_SER(matrixNy); + SST_SER(elementWidth); + SST_SER(lhsVecStartAddr); + SST_SER(rhsVecStartAddr); + SST_SER(ordinalWidth); + SST_SER(matrixNNZPerRow); + SST_SER(matrixRowIndicesStartAddr); + SST_SER(localRowStart); + SST_SER(localRowEnd); + SST_SER(matrixColumnIndicesStartAddr); + SST_SER(matrixElementsStartAddr); - SST_ELI_DOCUMENT_PARAMS( - { "matrix_nx", "Sets the horizontal dimension of the matrix", "10" }, - { "matrix_ny", "Sets the vertical dimension of the matrix (the number of rows)", "10" }, - { "element_width", "Sets the width of one matrix element, typically 8 for a double", "8" }, - { "lhs_start_addr", "Sets the start address of the LHS vector", "0" }, - { "rhs_start_addr", "Sets the start address of the RHS vector", "80" }, - { "local_row_start", "Sets the row at which this generator will start processing", "0" }, - { "local_row_end", "Sets the end at which rows will be processed by this generator", "10" }, - { "ordinal_width", "Sets the width of ordinals (indices) in the matrix, typically 4 or 8", "8"}, - { "matrix_row_indices_start_addr", "Sets the row indices start address for the matrix", "0" }, - { "matrix_col_indices_start_addr", "Sets the col indices start address for the matrix", "0" }, - { "matrix_element_start_addr", "Sets the start address of the elements array", "0" }, - { "iterations", "Sets the number of repeats to perform" }, - { "matrix_nnz_per_row", "Sets the number of non-zero elements per row", "9" } - ) -private: - Output* out; + SST_SER(out); + } + + ImplementSerializable(SST::Miranda::SPMVGenerator) + +private: uint64_t iterations; uint64_t matrixNx; uint64_t matrixNy; @@ -178,6 +200,8 @@ class SPMVGenerator : public RequestGenerator { uint64_t matrixColumnIndicesStartAddr; uint64_t matrixElementsStartAddr; + Output* out; + }; } diff --git a/src/sst/elements/miranda/generators/stake.h b/src/sst/elements/miranda/generators/stake.h index f3ba94fa13..d95b9580ba 100644 --- a/src/sst/elements/miranda/generators/stake.h +++ b/src/sst/elements/miranda/generators/stake.h @@ -42,60 +42,63 @@ namespace Miranda { class Stake : public RequestGenerator { public: - Stake( ComponentId_t id, Params& params ); - void build(Params& params); // Temporary while legacy constructor is getting deprecated + SST_ELI_REGISTER_SUBCOMPONENT_DERIVED( + Stake, + "miranda", + "Stake", + SST_ELI_ELEMENT_VERSION(1,0,0), + "Instantiates a RISC-V Spike instance to drive memory traffic", + SST::Miranda::RequestGenerator + ) + + SST_ELI_DOCUMENT_PARAMS( + { "verbose", "Sets the verbosity output of the generator", "0" }, + { "cores", "Sets the number of cores in the spike instance", "1" }, + { "mem_size", "Sets the RISC-V Spike memory subsystem size", "2048" }, + { "log", "Generate a log of the execution", "0" }, + { "isa", "Set the respective RISC-V ISA", "RV64IMAFDC" }, + { "pc", "Override the default ELF entry point", "0x80000000"}, + { "proxy_kernel", "Set the default proxy kernel", "pk"}, + { "bin", "Set the RISC-V ELF binary", "NULL"}, + { "args", "Set the RISC-V binary arguments", "NULL"}, + { "extension", "Specify the RoCC extension", "NULL" }, + { "extlib", "Shared library to load", "NULL" } + ) + + Stake( ComponentId_t id, Params& params ); + Stake() = default; ~Stake(); + void build(Params& params); // Temporary while legacy constructor is getting deprecated void generate(MirandaRequestQueue* q); bool isFinished(); void completed(); - void StakeRequest(uint64_t addr, uint32_t RegLen, - bool Read, bool Write, bool Atomic, bool Custom, - uint32_t Code ); + void StakeRequest(uint64_t addr, uint32_t RegLen, + bool Read, bool Write, bool Atomic, bool Custom, + uint32_t Code ); - SST_ELI_REGISTER_SUBCOMPONENT_DERIVED( - Stake, - "miranda", - "Stake", - SST_ELI_ELEMENT_VERSION(1,0,0), - "Instantiates a RISC-V Spike instance to drive memory traffic", - SST::Miranda::RequestGenerator - ) - - SST_ELI_DOCUMENT_PARAMS( - { "verbose", "Sets the verbosity output of the generator", "0" }, - { "cores", "Sets the number of cores in the spike instance", "1" }, - { "mem_size", "Sets the RISC-V Spike memory subsystem size", "2048" }, - { "log", "Generate a log of the execution", "0" }, - { "isa", "Set the respective RISC-V ISA", "RV64IMAFDC" }, - { "pc", "Override the default ELF entry point", "0x80000000"}, - { "proxy_kernel", "Set the default proxy kernel", "pk"}, - { "bin", "Set the RISC-V ELF binary", "NULL"}, - { "args", "Set the RISC-V binary arguments", "NULL"}, - { "extension", "Specify the RoCC extension", "NULL" }, - { "extlib", "Shared library to load", "NULL" } - ) + NotSerializable(SST::Miranda::Stake) private: - bool done; // holds the completion code of the sim - bool log; // log the Spike execution to a file - int rtn; // return code from the simulator - size_t cores; // number of RISC-V cores - uint64_t pc; // starting pc - std::string msize; // size of the memory subsystem - std::string isa; // isa string - std::string pk; // proxy kernel - std::string bin; // ELF binary - std::string args; // Binary args - std::string ext; // RoCC extension - std::string extlib; // extension library - - MirandaRequestQueue* MQ; // memory request queue - std::vector> make_mems(const char* arg); + bool done; // holds the completion code of the sim + bool log; // log the Spike execution to a file + int rtn; // return code from the simulator + size_t cores; // number of RISC-V cores + uint64_t pc; // starting pc + std::string msize; // size of the memory subsystem + std::string isa; // isa string + std::string pk; // proxy kernel + std::string bin; // ELF binary + std::string args; // Binary args + std::string ext; // RoCC extension + std::string extlib; // extension library + + MirandaRequestQueue* MQ; // memory request queue + std::vector> make_mems(const char* arg); Output* out; // output handle - sim_t *spike; // spike simulator instance + sim_t *spike; // spike simulator instance }; } diff --git a/src/sst/elements/miranda/generators/stencil3dbench.h b/src/sst/elements/miranda/generators/stencil3dbench.h index 65995ff54a..290ac2c299 100644 --- a/src/sst/elements/miranda/generators/stencil3dbench.h +++ b/src/sst/elements/miranda/generators/stencil3dbench.h @@ -28,13 +28,6 @@ namespace Miranda { class Stencil3DBenchGenerator : public RequestGenerator { public: - Stencil3DBenchGenerator( ComponentId_t id, Params& params ); - void build(Params& params); - ~Stencil3DBenchGenerator(); - void generate(MirandaRequestQueue* q); - bool isFinished(); - void completed(); - SST_ELI_REGISTER_SUBCOMPONENT( Stencil3DBenchGenerator, "miranda", @@ -55,6 +48,34 @@ class Stencil3DBenchGenerator : public RequestGenerator { { "iterations", "Sets the number of iterations to perform over this mesh", "1"} ) + Stencil3DBenchGenerator( ComponentId_t id, Params& params ); + Stencil3DBenchGenerator() = default; + ~Stencil3DBenchGenerator(); + void build(Params& params); + void generate(MirandaRequestQueue* q); + bool isFinished(); + void completed(); + + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::RequestGenerator::serialize_order(ser); + SST_SER(nX); + SST_SER(nY); + SST_SER(nZ); + SST_SER(datawidth); + + SST_SER(startZ); + SST_SER(endZ); + + SST_SER(currentZ); + SST_SER(currentItr); + SST_SER(maxItr); + + SST_SER(out); + } + + ImplementSerializable(SST::Miranda::Stencil3DBenchGenerator) + + private: void convertIndexToPosition(const uint32_t index, uint32_t* posX, uint32_t* posY, uint32_t* posZ); diff --git a/src/sst/elements/miranda/generators/streambench.h b/src/sst/elements/miranda/generators/streambench.h index a7cfc71a6f..9862be704c 100644 --- a/src/sst/elements/miranda/generators/streambench.h +++ b/src/sst/elements/miranda/generators/streambench.h @@ -28,13 +28,6 @@ namespace Miranda { class STREAMBenchGenerator : public RequestGenerator { public: - STREAMBenchGenerator( ComponentId_t id, Params& params ); - void build(Params& params); - ~STREAMBenchGenerator(); - void generate(MirandaRequestQueue* q); - bool isFinished(); - void completed(); - SST_ELI_REGISTER_SUBCOMPONENT( STREAMBenchGenerator, "miranda", @@ -54,6 +47,31 @@ class STREAMBenchGenerator : public RequestGenerator { { "start_c", "Sets the start address of the array c", "2048" } ) + STREAMBenchGenerator( ComponentId_t id, Params& params ); + STREAMBenchGenerator() = default; + ~STREAMBenchGenerator(); + void build(Params& params); + void generate(MirandaRequestQueue* q); + bool isFinished(); + void completed(); + + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::RequestGenerator::serialize_order(ser); + SST_SER(reqLength); + + SST_SER(start_a); + SST_SER(start_b); + SST_SER(start_c); + + SST_SER(n); + SST_SER(n_per_call); + SST_SER(i); + + SST_SER(out); + } + + ImplementSerializable(SST::Miranda::STREAMBenchGenerator) + private: uint64_t reqLength; diff --git a/src/sst/elements/miranda/generators/streambench_customcmd.h b/src/sst/elements/miranda/generators/streambench_customcmd.h index 99cf7f6aac..82c0ba3a0c 100644 --- a/src/sst/elements/miranda/generators/streambench_customcmd.h +++ b/src/sst/elements/miranda/generators/streambench_customcmd.h @@ -28,13 +28,6 @@ namespace Miranda { class STREAMBenchGenerator_CustomCmd : public RequestGenerator { public: - STREAMBenchGenerator_CustomCmd( ComponentId_t id, Params& params ); - void build(Params& params); - ~STREAMBenchGenerator_CustomCmd(); - void generate(MirandaRequestQueue* q); - bool isFinished(); - void completed(); - SST_ELI_REGISTER_SUBCOMPONENT( STREAMBenchGenerator_CustomCmd, "miranda", @@ -56,6 +49,36 @@ class STREAMBenchGenerator_CustomCmd : public RequestGenerator { { "read_cmd", "Sets the custom opcode for reads", "0xFFFF" } ) + STREAMBenchGenerator_CustomCmd( ComponentId_t id, Params& params ); + STREAMBenchGenerator_CustomCmd() = default; + ~STREAMBenchGenerator_CustomCmd(); + void build(Params& params); + void generate(MirandaRequestQueue* q); + bool isFinished(); + void completed(); + + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::RequestGenerator::serialize_order(ser); + SST_SER(reqLength); + + SST_SER(start_a); + SST_SER(start_b); + SST_SER(start_c); + + SST_SER(n); + SST_SER(n_per_call); + SST_SER(i); + + SST_SER(custom_write_opcode); + SST_SER(custom_read_opcode); + + SST_SER(out); + } + + ImplementSerializable(SST::Miranda::STREAMBenchGenerator_CustomCmd) + + + private: uint64_t reqLength; @@ -67,8 +90,8 @@ class STREAMBenchGenerator_CustomCmd : public RequestGenerator { uint64_t n_per_call; uint64_t i; - uint32_t custom_write_opcode; - uint32_t custom_read_opcode; + uint32_t custom_write_opcode; + uint32_t custom_read_opcode; Output* out; diff --git a/src/sst/elements/miranda/mirandaCPU.cc b/src/sst/elements/miranda/mirandaCPU.cc index 136ed82610..da93b13e63 100644 --- a/src/sst/elements/miranda/mirandaCPU.cc +++ b/src/sst/elements/miranda/mirandaCPU.cc @@ -38,37 +38,38 @@ RequestGenCPU::RequestGenCPU(SST::ComponentId_t id, SST::Params& params) : maxRequestsPending[WRITE] = params.find("maxstorememreqpending", 16); maxRequestsPending[CUSTOM] = params.find("maxcustommemreqpending", 16); - requestsPending[READ] = requestsPending[WRITE] = requestsPending[CUSTOM] = 0; + requestsPending[READ] = requestsPending[WRITE] = requestsPending[CUSTOM] = 0; out->verbose(CALL_INFO, 1, 0, "Configured CPU to allow %" PRIu32 " maximum Load requests to be memory to be outstanding.\n", - maxRequestsPending[READ]); + maxRequestsPending[READ]); out->verbose(CALL_INFO, 1, 0, "Configured CPU to allow %" PRIu32 " maximum Store requests to be memory to be outstanding.\n", - maxRequestsPending[WRITE]); + maxRequestsPending[WRITE]); out->verbose(CALL_INFO, 1, 0, "Configured CPU to allow %" PRIu32 " maximum Custom requests to be memory to be outstanding.\n", - maxRequestsPending[CUSTOM]); + maxRequestsPending[CUSTOM]); - std::string cpuClock = params.find("clock", "2GHz"); + std::string cpuClock = params.find("clock", "2GHz"); clockHandler = new Clock::Handler2(this); timeConverter = registerClock(cpuClock, clockHandler ); out->verbose(CALL_INFO, 1, 0, "CPU clock configured for %s\n", cpuClock.c_str()); - cache_link = loadUserSubComponent("memory", ComponentInfo::SHARE_NONE, - &timeConverter, new Interfaces::StandardMem::Handler2(this) ); - if (!cache_link) { + cache_link = loadUserSubComponent("memory", ComponentInfo::SHARE_NONE, + &timeConverter, new Interfaces::StandardMem::Handler2(this) ); + if (!cache_link) { std::string interfaceName = params.find("memoryinterface", "memHierarchy.standardInterface"); out->verbose(CALL_INFO, 1, 0, "Memory interface to be loaded is: %s\n", interfaceName.c_str()); Params interfaceParams = params.get_scoped_params("memoryinterfaceparams"); - interfaceParams.insert("port", "cache_link"); + interfaceParams.insert("port", "cache_link"); cache_link = loadAnonymousSubComponent(interfaceName, "memory", 0, ComponentInfo::SHARE_PORTS | ComponentInfo::INSERT_STATS, - interfaceParams, &timeConverter, new Interfaces::StandardMem::Handler2(this)); + interfaceParams, &timeConverter, new Interfaces::StandardMem::Handler2(this)); - if (!cache_link) - out->fatal(CALL_INFO, -1, "%s, Error loading memory interface\n", getName().c_str()); - } + if (!cache_link) { + out->fatal(CALL_INFO, -1, "%s, Error loading memory interface\n", getName().c_str()); + } + } - stdMemHandlers = new StdMemHandler(this, out); + stdMemHandlers = new StdMemHandler(this, out); maxOpLookup = params.find("max_reorder_lookups", 16); @@ -80,13 +81,13 @@ RequestGenCPU::RequestGenCPU(SST::ComponentId_t id, SST::Params& params) : if( pageSize % cacheLine > 0 ) { out->fatal(CALL_INFO, -8, "Error: Miranda memory configuration. Page size=%" PRIu64 ", is not a multiple of cache line size: %" PRIu64 "\n", - pageSize, cacheLine); + pageSize, cacheLine); } MirandaPageMappingPolicy policy = MirandaPageMappingPolicy::LINEAR; std::string policyStr = params.find("pagemap", "linear"); - std::string pageMapStr = params.find("pagemapname", "miranda"); + std::string pageMapStr = params.find("pagemapname", "miranda"); if(policyStr == "RANDOMIZED" || policyStr == "randomized") { policy = MirandaPageMappingPolicy::RANDOMIZED; @@ -96,56 +97,67 @@ RequestGenCPU::RequestGenCPU(SST::ComponentId_t id, SST::Params& params) : out->fatal(CALL_INFO, -8, "Error: unknown page mapping type: \'%s\'\n", policyStr.c_str()); } - memMgr = new MirandaMemoryManager(out, pageSize, pageCount, policy); + memMgr = new MirandaMemoryManager(out, pageSize, pageCount, policy); - reqGen = loadUserSubComponent("generator"); - if (reqGen) { - out->verbose(CALL_INFO, 1, 0, "Generator loaded successfully.\n"); + // Generators can be given in 3 ways. We will search for them in the following order + // 1. In the `generator` subcomponent + // 2. In the `generator` parameter + // 3. Received on the `src` port + // Method 3 can be used to send multiple generators to this CPU. Otherwise only a single + // generator will be used. + reqGen = loadUserSubComponent("generator"); + if (reqGen) { + + out->verbose(CALL_INFO, 1, 0, "Generator loaded successfully.\n"); registerAsPrimaryComponent(); primaryComponentDoNotEndSim(); - } else { + } else { + std::string reqGenModName = params.find("generator", ""); - if ( ! reqGenModName.empty() ) { + if ( ! reqGenModName.empty() ) { - out->verbose(CALL_INFO, 1, 0, "Request generator to be loaded is: %s\n", reqGenModName.c_str()); - Params genParams = params.get_scoped_params("generatorParams"); - reqGen = loadAnonymousSubComponent( reqGenModName, "generator", 0, ComponentInfo::INSERT_STATS, genParams); - if(NULL == reqGen) { - out->fatal(CALL_INFO, -1, "Failed to load generator: %s\n", reqGenModName.c_str()); - } else { - out->verbose(CALL_INFO, 1, 0, "Generator loaded successfully.\n"); - } + out->verbose(CALL_INFO, 1, 0, "Request generator to be loaded is: %s\n", reqGenModName.c_str()); + Params genParams = params.get_scoped_params("generatorParams"); + reqGen = loadAnonymousSubComponent( reqGenModName, "generator", 0, ComponentInfo::INSERT_STATS, genParams); + if(NULL == reqGen) { + out->fatal(CALL_INFO, -1, "Failed to load generator: %s\n", reqGenModName.c_str()); + } else { + out->verbose(CALL_INFO, 1, 0, "Generator loaded successfully.\n"); + } - registerAsPrimaryComponent(); - primaryComponentDoNotEndSim(); + registerAsPrimaryComponent(); + primaryComponentDoNotEndSim(); } else if ( isPortConnected("src") ) { - // TODO create a generator that gets data from a port - out->verbose(CALL_INFO, 1, 0, "getting generators from a link\n"); - srcLink = configureLink( "src", "50ps", new Event::Handler2(this)); - if ( NULL == srcLink ) { - out->fatal(CALL_INFO, -1, "Failed to configure src link\n"); - } + + // TODO create a generator that gets data from a port + out->verbose(CALL_INFO, 1, 0, "getting generators from a link\n"); + srcLink = configureLink( "src", "50ps", new Event::Handler2(this)); + if ( NULL == srcLink ) { + out->fatal(CALL_INFO, -1, "Failed to configure src link\n"); + } } else { - out->fatal(CALL_INFO, -1, "Failed to find a generator or src port\n"); + + out->fatal(CALL_INFO, -1, "Failed to find a generator or src port\n"); + } - } + } - statReqs[READ] = registerStatistic( "read_reqs" ); - statReqs[WRITE] = registerStatistic( "write_reqs" ); - statReqs[CUSTOM] = registerStatistic( "custom_reqs" ); + statReqs[READ] = registerStatistic( "read_reqs" ); + statReqs[WRITE] = registerStatistic( "write_reqs" ); + statReqs[CUSTOM] = registerStatistic( "custom_reqs" ); statSplitReqs[READ] = registerStatistic( "split_read_reqs" ); statSplitReqs[WRITE] = registerStatistic( "split_write_reqs" ); statSplitReqs[CUSTOM] = registerStatistic( "split_custom_reqs" ); statCyclesWithIssue = registerStatistic( "cycles_with_issue" ); statCyclesWithoutIssue = registerStatistic( "cycles_no_issue" ); - statBytes[READ] = registerStatistic( "total_bytes_read" ); - statBytes[WRITE] = registerStatistic( "total_bytes_write" ); - statBytes[CUSTOM] = registerStatistic( "total_bytes_custom" ); - statReqLatency = registerStatistic( "req_latency" ); + statBytes[READ] = registerStatistic( "total_bytes_read" ); + statBytes[WRITE] = registerStatistic( "total_bytes_write" ); + statBytes[CUSTOM] = registerStatistic( "total_bytes_custom" ); + statReqLatency = registerStatistic( "req_latency" ); statTime = registerStatistic( "time" ); statCyclesHitFence = registerStatistic( "cycles_hit_fence" ); statMaxIssuePerCycle = registerStatistic( "cycles_max_issue" ); @@ -154,8 +166,6 @@ RequestGenCPU::RequestGenCPU(SST::ComponentId_t id, SST::Params& params) : reqMaxPerCycle = params.find("max_reqs_cycle", 2); - - out->verbose(CALL_INFO, 1, 0, "Miranda CPU Configuration:\n"); out->verbose(CALL_INFO, 1, 0, "- Max requests per cycle: %" PRIu32 "\n", reqMaxPerCycle); out->verbose(CALL_INFO, 1, 0, "- Max reorder lookups %" PRIu32 "\n", maxOpLookup); @@ -179,7 +189,6 @@ void RequestGenCPU::init(unsigned int phase) { } void RequestGenCPU::handleSrcEvent( Event* ev ) { - MirandaReqEvent* event = static_cast(ev); out->verbose(CALL_INFO, 2, 0, "got %lu generators\n", event->generators.size() ); @@ -193,7 +202,6 @@ void RequestGenCPU::handleSrcEvent( Event* ev ) { } void RequestGenCPU::loadGenerator( MirandaReqEvent* event ) { - std::string& generator = event->generators.front().first; SST::Params& params = event->generators.front().second; loadGenerator( generator, params ); @@ -201,7 +209,6 @@ void RequestGenCPU::loadGenerator( MirandaReqEvent* event ) { } void RequestGenCPU::loadGenerator( const std::string& name, SST::Params& params) { - out->verbose(CALL_INFO, 1, 0, "generator to be loaded is: %s\n", name.c_str()); reqGen = loadAnonymousSubComponent( name, "generator", 0, ComponentInfo::SHARE_NONE, params ); @@ -215,16 +222,16 @@ void RequestGenCPU::loadGenerator( const std::string& name, SST::Params& params) void RequestGenCPU::handleEvent( Interfaces::StandardMem::Request* ev) { out->verbose(CALL_INFO, 2, 0, "Recv event for processing from interface\n"); - Interfaces::StandardMem::Request::id_t reqID = ev->getID(); + Interfaces::StandardMem::Request::id_t reqID = ev->getID(); std::map::iterator reqFind = requestsInFlight.find(reqID); if(reqFind == requestsInFlight.end()) { out->fatal(CALL_INFO, -1, "Unable to find request %" PRIu64 " in request map.\n", reqID); - } else{ + } else { CPURequest* cpuReq = reqFind->second; out->verbose(CALL_INFO, 4, 0, "Miranda request located ID=%" PRIu64 ", contains %" PRIu32 " parts, issue time=%" PRIu64 ", time now=%" PRIu64 "\n", - cpuReq->getOriginalReqID(), cpuReq->countParts(), cpuReq->getIssueTime(), getCurrentSimTimeNano()); + cpuReq->getOriginalReqID(), cpuReq->countParts(), cpuReq->getIssueTime(), getCurrentSimTimeNano()); statReqLatency->addData((getCurrentSimTimeNano() - cpuReq->getIssueTime())); requestsInFlight.erase(reqFind); @@ -233,13 +240,13 @@ void RequestGenCPU::handleEvent( Interfaces::StandardMem::Request* ev) { cpuReq->decPartCount(); // Decrement pending requests, we have recv'd a response - ev->handle(stdMemHandlers); + ev->handle(stdMemHandlers); // If all the parts of this request are now completed then we will mark it for // deletion and update any pending requests which are depending on us if(cpuReq->completed()) { out->verbose(CALL_INFO, 4, 0, "-> Entry has all parts satisfied, removing ID=%" PRIu64 ", total processing time: %" PRIu64 "ns\n", - cpuReq->getOriginalReqID(), (getCurrentSimTimeNano() - cpuReq->getIssueTime())); + cpuReq->getOriginalReqID(), (getCurrentSimTimeNano() - cpuReq->getIssueTime())); // Notify every pending request that there may be a satisfied dependency for(uint32_t i = 0; i < pendingRequests.size(); ++i) { @@ -274,8 +281,9 @@ void RequestGenCPU::issueCustomRequest(CustomOpRequest* req) { out->verbose(CALL_INFO, 4, 0, "Issue request: address=0x%" PRIx64 ", size=%" PRIu64 ", operation=%s\n", reqAddress, reqLength, "CUSTOM"); - if (statBytes[CUSTOM] != nullptr) + if (statBytes[CUSTOM] != nullptr) { statBytes[CUSTOM]->addData(reqLength); + } Interfaces::StandardMem::CustomReq* request = new Interfaces::StandardMem::CustomReq(req->getPayload()); @@ -288,8 +296,9 @@ void RequestGenCPU::issueCustomRequest(CustomOpRequest* req) { requestsPending[CUSTOM]++; - if (statReqs[CUSTOM] != nullptr) + if (statReqs[CUSTOM] != nullptr) { statReqs[CUSTOM]->addData(1); + } } void RequestGenCPU::issueRequest(MemoryOpRequest* req) { @@ -302,8 +311,9 @@ void RequestGenCPU::issueRequest(MemoryOpRequest* req) { out->verbose(CALL_INFO, 4, 0, "Issue request: address=0x%" PRIx64 ", length=%" PRIu64 ", operation=%s, cache line offset=%" PRIu64 "\n", reqAddress, reqLength, (isRead ? "READ" : "WRITE"), lineOffset); - if (statBytes[operation] != nullptr) + if (statBytes[operation] != nullptr) { statBytes[operation]->addData(reqLength); + } if(lineOffset + reqLength > cacheLine) { // Request is for a split operation (i.e. split over cache lines) @@ -316,10 +326,10 @@ void RequestGenCPU::issueRequest(MemoryOpRequest* req) { const uint64_t lowerAddress = memMgr->mapAddress(reqAddress); const uint64_t upperAddress = memMgr->mapAddress((lowerAddress - lowerAddress % cacheLine) + cacheLine); - out->verbose(CALL_INFO, 4, 0, "Issuing a split cache line operation:\n"); + out->verbose(CALL_INFO, 4, 0, "Issuing a split cache line operation:\n"); out->verbose(CALL_INFO, 4, 0, "L -> Address: %" PRIu64 ", Length=%" PRIu64 "\n", lowerAddress, lowerLength); - out->verbose(CALL_INFO, 4, 0, "U -> Address: %" PRIu64 ", Length=%" PRIu64 "\n", + out->verbose(CALL_INFO, 4, 0, "U -> Address: %" PRIu64 ", Length=%" PRIu64 "\n", upperAddress, upperLength); Interfaces::StandardMem::Request *reqLower; @@ -353,8 +363,9 @@ void RequestGenCPU::issueRequest(MemoryOpRequest* req) { requestsPending[operation] += 2; // Keep track of split requests - if (statSplitReqs[operation] != nullptr) + if (statSplitReqs[operation] != nullptr) { statSplitReqs[operation]->addData(1); + } } else { // This is not a split load, i.e. issue in a single transaction @@ -377,8 +388,9 @@ void RequestGenCPU::issueRequest(MemoryOpRequest* req) { requestsPending[operation]++; - if (statReqs[operation] != nullptr) + if (statReqs[operation] != nullptr) { statReqs[operation]->addData(1); + } } } @@ -455,7 +467,7 @@ bool RequestGenCPU::clockTick(SST::Cycle_t cycle) { break; } - // Only a certain number of lookups are allowed, if we exceed this then we + // Only a certain number of lookups are allowed, if we exceed this then we // must exit the issue loop if(i == maxOpLookup) { out->verbose(CALL_INFO, 2, 0, "Hit maximum reorder limit this cycle, no further operations will issue.\n"); @@ -463,83 +475,83 @@ bool RequestGenCPU::clockTick(SST::Cycle_t cycle) { break; } - GeneratorRequest* nxtRq = pendingRequests.at(i); - ReqOperation op = nxtRq->getOperation(); + GeneratorRequest* nxtRq = pendingRequests.at(i); + ReqOperation op = nxtRq->getOperation(); - if(op == REQ_FENCE) { - if(0 == requestsInFlight.size()) { - out->verbose(CALL_INFO, 4, 0, "Fence operation completed, no pending requests, will be retired.\n"); + if(op == REQ_FENCE) { + if(0 == requestsInFlight.size()) { + out->verbose(CALL_INFO, 4, 0, "Fence operation completed, no pending requests, will be retired.\n"); - // Keep record we will delete fence at i - delReqs.push_back(i); + // Keep record we will delete fence at i + delReqs.push_back(i); - // Delete the fence - delete nxtRq; - } else { - out->verbose(CALL_INFO, 4, 0, "Fence operation in flight (>0 pending requests), stall.\n"); - } + // Delete the fence + delete nxtRq; + } else { + out->verbose(CALL_INFO, 4, 0, "Fence operation in flight (>0 pending requests), stall.\n"); + } - statCyclesHitFence->addData(1); + statCyclesHitFence->addData(1); - // Fence operations do now allow anything else to complete in this cycle - break; - } else if (op == CUSTOM) { - if (requestsPending[CUSTOM] < maxRequestsPending[CUSTOM]) { - out->verbose(CALL_INFO, 4, 0, "Will attempt to issue as free slots in the load/store unit.\n"); + // Fence operations do now allow anything else to complete in this cycle + break; + } else if (op == CUSTOM) { + if (requestsPending[CUSTOM] < maxRequestsPending[CUSTOM]) { + out->verbose(CALL_INFO, 4, 0, "Will attempt to issue as free slots in the load/store unit.\n"); - if(nxtRq->canIssue()) { - issued = true; - reqsIssuedThisCycle++; - out->verbose(CALL_INFO, 4, 0, "Request %" PRIu64 " encountered, cleared to be issued, %" PRIu32 " issued this cycle.\n", - nxtRq->getRequestID(), reqsIssuedThisCycle); + if(nxtRq->canIssue()) { + issued = true; + reqsIssuedThisCycle++; + out->verbose(CALL_INFO, 4, 0, "Request %" PRIu64 " encountered, cleared to be issued, %" PRIu32 " issued this cycle.\n", + nxtRq->getRequestID(), reqsIssuedThisCycle); - // Keep record we will delete at index i - delReqs.push_back(i); + // Keep record we will delete at index i + delReqs.push_back(i); - issueCustomRequest(static_cast(nxtRq)); + issueCustomRequest(static_cast(nxtRq)); - delete nxtRq; - } - } - } else if (op == READ || op == WRITE) { - if( requestsPending[op] < maxRequestsPending[op] ) { - auto memOpReq = static_cast(nxtRq); - out->verbose(CALL_INFO, 4, 0, "Will attempt to issue as free slots in the load/store unit.\n"); + delete nxtRq; + } + } + } else if (op == READ || op == WRITE) { + if( requestsPending[op] < maxRequestsPending[op] ) { + auto memOpReq = static_cast(nxtRq); + out->verbose(CALL_INFO, 4, 0, "Will attempt to issue as free slots in the load/store unit.\n"); - if(nxtRq->canIssue()) { - issued = true; - reqsIssuedThisCycle++; + if(nxtRq->canIssue()) { + issued = true; + reqsIssuedThisCycle++; - out->verbose(CALL_INFO, 4, 0, "Request %" PRIu64 " encountered, cleared to be issued, %" PRIu32 " issued this cycle.\n", - nxtRq->getRequestID(), reqsIssuedThisCycle); + out->verbose(CALL_INFO, 4, 0, "Request %" PRIu64 " encountered, cleared to be issued, %" PRIu32 " issued this cycle.\n", + nxtRq->getRequestID(), reqsIssuedThisCycle); - // Keep record we will delete at index i - delReqs.push_back(i); + // Keep record we will delete at index i + delReqs.push_back(i); - issueRequest(memOpReq); + issueRequest(memOpReq); - delete nxtRq; + delete nxtRq; + } else { + out->verbose(CALL_INFO, 4, 0, "Request %" PRIu64 " in queue, has dependencies which are not satisfied, wait.\n", + nxtRq->getRequestID()); + } + } else { + out->verbose(CALL_INFO, 4, 0, "All load/store/custom slots occupied, no more issues will be attempted.\n"); + break; + } } else { - out->verbose(CALL_INFO, 4, 0, "Request %" PRIu64 " in queue, has dependencies which are not satisfied, wait.\n", - nxtRq->getRequestID()); - } - } else { - out->verbose(CALL_INFO, 4, 0, "All load/store/custom slots occupied, no more issues will be attempted.\n"); - break; - } - } else { - out->fatal(CALL_INFO, -1, "Error, invalid operation \n"); - } - } + out->fatal(CALL_INFO, -1, "Error, invalid operation \n"); + } + } pendingRequests.erase(delReqs); if(issued) { - statCyclesWithIssue->addData(1); + statCyclesWithIssue->addData(1); } else { - out->verbose(CALL_INFO, 4, 0, "Will not issue, not free slots in load/store unit.\n"); - statCyclesWithoutIssue->addData(1); + out->verbose(CALL_INFO, 4, 0, "Will not issue, not free slots in load/store unit.\n"); + statCyclesWithoutIssue->addData(1); } return false; diff --git a/src/sst/elements/miranda/mirandaCPU.h b/src/sst/elements/miranda/mirandaCPU.h index f3ef022c3b..28b0b7c901 100644 --- a/src/sst/elements/miranda/mirandaCPU.h +++ b/src/sst/elements/miranda/mirandaCPU.h @@ -35,6 +35,7 @@ class CPURequest { public: CPURequest(const uint64_t origID) : originalID(origID), issueTime(0), outstandingParts(0) {} + CPURequest() = default; void incPartCount() { outstandingParts++; } void decPartCount() { outstandingParts--; } bool completed() const { return 0 == outstandingParts; } @@ -42,6 +43,13 @@ class CPURequest { uint64_t getIssueTime() const { return issueTime; } uint64_t getOriginalReqID() const { return originalID; } uint32_t countParts() const { return outstandingParts; } + + void serialize_order(SST::Core::Serialization::serializer& ser) { + SST_SER(originalID); + SST_SER(issueTime); + SST_SER(outstandingParts); + } + protected: uint64_t originalID; uint64_t issueTime; @@ -60,11 +68,19 @@ class RequestGenCPU : public SST::Component { public: friend class RequestGenCPU; StdMemHandler(RequestGenCPU* cpuInst, SST::Output* out) : SST::Interfaces::StandardMem::RequestHandler(out), cpu(cpuInst) {} + StdMemHandler() = default; virtual ~StdMemHandler() {} virtual void handle(SST::Interfaces::StandardMem::ReadResp* rsp) override; virtual void handle(SST::Interfaces::StandardMem::WriteResp* rsp) override; virtual void handle(SST::Interfaces::StandardMem::CustomResp* rsp) override; + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Interfaces::StandardMem::RequestHandler::serialize_order(ser); + SST_SER(cpu); + } + + ImplementSerializable(SST::Miranda::RequestGenCPU::StdMemHandler) + RequestGenCPU* cpu; }; @@ -122,8 +138,47 @@ class RequestGenCPU : public SST::Component { { "memory", "The memory interface to use (e.g., interface to caches)", "SST::Interfaces::StandardMem" } ) + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Component::serialize_order(ser); + SST_SER(out); + + SST_SER(timeConverter); + SST_SER(clockHandler); + SST_SER(reqGen); + SST_SER(requestsInFlight); + SST_SER(cache_link); + SST_SER(srcLink); + SST_SER(srcReqEvent); + SST_SER(stdMemHandlers); + + SST_SER(pendingRequests); + SST_SER(memMgr); + + SST_SER(maxRequestsPending); + SST_SER(requestsPending); + SST_SER(reqMaxPerCycle); + SST_SER(cacheLine); + SST_SER(maxOpLookup); + + SST_SER(statReqs); + SST_SER(statSplitReqs); + SST_SER(statCyclesWithIssue); + SST_SER(statMaxIssuePerCycle); + SST_SER(statCyclesWithoutIssue); + SST_SER(statBytes); + SST_SER(statReqLatency); + SST_SER(statTime); + SST_SER(statCyclesHitFence); + SST_SER(statCyclesHitReorderLimit); + SST_SER(statCycles); + + } + + ImplementSerializable(SST::Miranda::RequestGenCPU) + + private: - RequestGenCPU(); // for serialization only + RequestGenCPU() = default; // for serialization only RequestGenCPU(const RequestGenCPU&); // do not implement void operator=(const RequestGenCPU&); // do not implement ~RequestGenCPU(); @@ -156,12 +211,12 @@ class RequestGenCPU : public SST::Component { uint64_t cacheLine; uint32_t maxOpLookup; - Statistic* statReqs[OPCOUNT]; - Statistic* statSplitReqs[OPCOUNT]; + Statistic* statReqs[OPCOUNT] = {nullptr, nullptr, nullptr, nullptr}; + Statistic* statSplitReqs[OPCOUNT] = {nullptr, nullptr, nullptr, nullptr}; Statistic* statCyclesWithIssue; Statistic* statMaxIssuePerCycle; Statistic* statCyclesWithoutIssue; - Statistic* statBytes[OPCOUNT]; + Statistic* statBytes[OPCOUNT] = {nullptr, nullptr, nullptr, nullptr}; Statistic* statReqLatency; Statistic* statTime; Statistic* statCyclesHitFence; diff --git a/src/sst/elements/miranda/mirandaEvent.h b/src/sst/elements/miranda/mirandaEvent.h index 16f560e814..fc049e9539 100644 --- a/src/sst/elements/miranda/mirandaEvent.h +++ b/src/sst/elements/miranda/mirandaEvent.h @@ -26,20 +26,20 @@ namespace Miranda { class MirandaReqEvent : public SST::Event { public: + /* struct Generator { std::string name; SST::Params params; }; + */ std::deque< std::pair< std::string, SST::Params> > generators; - uint64_t key; -private: void serialize_order(SST::Core::Serialization::serializer &ser) override { - Event::serialize_order(ser); - SST_SER(key); + SST::Event::serialize_order(ser); SST_SER(generators); + SST_SER(key); } ImplementSerializable(SST::Miranda::MirandaReqEvent); @@ -50,7 +50,7 @@ class MirandaRspEvent : public SST::Event { uint64_t key; private: void serialize_order(SST::Core::Serialization::serializer &ser) override { - Event::serialize_order(ser); + SST::Event::serialize_order(ser); SST_SER(key); } ImplementSerializable(SST::Miranda::MirandaRspEvent); diff --git a/src/sst/elements/miranda/mirandaGenerator.h b/src/sst/elements/miranda/mirandaGenerator.h index de3b354082..28ad6e208e 100644 --- a/src/sst/elements/miranda/mirandaGenerator.h +++ b/src/sst/elements/miranda/mirandaGenerator.h @@ -32,12 +32,12 @@ typedef enum { READ, WRITE, REQ_FENCE, - CUSTOM, - OPCOUNT + CUSTOM, + OPCOUNT } ReqOperation; -class GeneratorRequest { +class GeneratorRequest : public SST::Core::Serialization::serializable { public: GeneratorRequest() { reqID = nextGeneratorRequestID++; @@ -77,6 +77,17 @@ class GeneratorRequest { void setIssueTime(const uint64_t now) { issueTime = now; } + + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + //SST::Core::Serialization::serializable::serialize_order(ser); + SST_SER(reqID); + SST_SER(issueTime); + SST_SER(dependsOn); + SST_SER(nextGeneratorRequestID); + } + + ImplementVirtualSerializable(SST::Miranda::GeneratorRequest) + protected: uint64_t reqID; uint64_t issueTime; @@ -88,33 +99,30 @@ class GeneratorRequest { template class MirandaRequestQueue { public: - MirandaRequestQueue() { - theQ = (QueueType*) malloc(sizeof(QueueType) * 16); - maxCapacity = 16; - curSize = 0; - } - ~MirandaRequestQueue() { - free(theQ); - } - - bool empty() const { - return 0 == curSize; - } - - void resize(const uint32_t newSize) { -// printf("Resizing MirandaQueue from: %" PRIu32 " to %" PRIu32 "\n", -// curSize, newSize); - - QueueType * newQ = (QueueType *) malloc(sizeof(QueueType) * newSize); - for(uint32_t i = 0; i < curSize; ++i) { - newQ[i] = theQ[i]; - } - - free(theQ); - theQ = newQ; - maxCapacity = newSize; - curSize = std::min(curSize, newSize); - } + MirandaRequestQueue() { + theQ = (QueueType*) malloc(sizeof(QueueType) * 16); + maxCapacity = 16; + curSize = 0; + } + ~MirandaRequestQueue() { + free(theQ); + } + + bool empty() const { + return 0 == curSize; + } + + void resize(const uint32_t newSize) { + QueueType * newQ = (QueueType *) malloc(sizeof(QueueType) * newSize); + for(uint32_t i = 0; i < curSize; ++i) { + newQ[i] = theQ[i]; + } + + free(theQ); + theQ = newQ; + maxCapacity = newSize; + curSize = std::min(curSize, newSize); + } uint32_t size() const { return curSize; @@ -124,72 +132,92 @@ class MirandaRequestQueue { return maxCapacity; } - QueueType at(const uint32_t index) { - return theQ[index]; - } + QueueType at(const uint32_t index) { + return theQ[index]; + } - void erase(const std::vector eraseList) { + void erase(const std::vector eraseList) { if(0 == eraseList.size()) { return; } - QueueType* newQ = (QueueType*) malloc(sizeof(QueueType) * maxCapacity); + QueueType* newQ = (QueueType*) malloc(sizeof(QueueType) * maxCapacity); - uint32_t nextSkipIndex = 0; - uint32_t nextSkip = eraseList.at(nextSkipIndex); - uint32_t nextNewQIndex = 0; + uint32_t nextSkipIndex = 0; + uint32_t nextSkip = eraseList.at(nextSkipIndex); + uint32_t nextNewQIndex = 0; - for(uint32_t i = 0; i < curSize; ++i) { - if(nextSkip == i) { - nextSkipIndex++; + for(uint32_t i = 0; i < curSize; ++i) { + if(nextSkip == i) { + nextSkipIndex++; - if(nextSkipIndex >= eraseList.size()) { - nextSkip = curSize; - } else { - nextSkip = eraseList.at(nextSkipIndex); - } - } else { - newQ[nextNewQIndex] = theQ[i]; - nextNewQIndex++; - } - } + if(nextSkipIndex >= eraseList.size()) { + nextSkip = curSize; + } else { + nextSkip = eraseList.at(nextSkipIndex); + } + } else { + newQ[nextNewQIndex] = theQ[i]; + nextNewQIndex++; + } + } - free(theQ); + free(theQ); - theQ = newQ; + theQ = newQ; curSize = nextNewQIndex; - } + } void push_back(QueueType t) { - if(curSize == maxCapacity) { - resize(maxCapacity + 16); - } + if(curSize == maxCapacity) { + resize(maxCapacity + 16); + } + + theQ[curSize] = t; + curSize++; + } + + void serialize_order(SST::Core::Serialization::serializer& ser) { + //int theQ_size = sizeof(QueueType) * curSize; + SST_SER(SST::Core::Serialization::array(theQ, curSize)); + SST_SER(maxCapacity); + SST_SER(curSize); + } - theQ[curSize] = t; - curSize++; - } private: - QueueType* theQ; - uint32_t maxCapacity; - uint32_t curSize; + QueueType* theQ; + uint32_t maxCapacity; + uint32_t curSize; }; class MemoryOpRequest : public GeneratorRequest { public: - MemoryOpRequest(const uint64_t cAddr, + MemoryOpRequest(const uint64_t cAddr, const uint64_t cLength, const ReqOperation cOpType) : GeneratorRequest(), addr(cAddr), length(cLength), op(cOpType) - { assert (op == READ || op == WRITE); } - + { + assert (op == READ || op == WRITE); + } + MemoryOpRequest() = default; ~MemoryOpRequest() {} + ReqOperation getOperation() const { return op; } bool isRead() const { return op == READ; } bool isWrite() const { return op == WRITE; } uint64_t getAddress() const { return addr; } uint64_t getLength() const { return length; } + void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::GeneratorRequest::serialize_order(ser); + SST_SER(addr); + SST_SER(length); + SST_SER(op); + } + + ImplementSerializable(SST::Miranda::MemoryOpRequest) + protected: uint64_t addr; uint64_t length; @@ -200,11 +228,19 @@ class CustomOpRequest : public GeneratorRequest { public: CustomOpRequest(Interfaces::StandardMem::CustomData* cData) : GeneratorRequest(), data(cData) {} + CustomOpRequest() = default; ~CustomOpRequest() {} ReqOperation getOperation() const { return CUSTOM; } Interfaces::StandardMem::CustomData* getPayload() { return data; } + void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::GeneratorRequest::serialize_order(ser); + SST_SER(data); + } + + ImplementSerializable(SST::Miranda::CustomOpRequest) + protected: Interfaces::StandardMem::CustomData* data; }; @@ -214,6 +250,13 @@ class FenceOpRequest : public GeneratorRequest { FenceOpRequest() : GeneratorRequest() {} ~FenceOpRequest() {} ReqOperation getOperation() const { return REQ_FENCE; } + + void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::Miranda::GeneratorRequest::serialize_order(ser); + } + + ImplementSerializable(SST::Miranda::FenceOpRequest) + }; class RequestGenerator : public SubComponent { @@ -222,11 +265,19 @@ class RequestGenerator : public SubComponent { SST_ELI_REGISTER_SUBCOMPONENT_API(SST::Miranda::RequestGenerator) RequestGenerator( ComponentId_t id, Params& params) : SubComponent(id) {} + RequestGenerator() = default; ~RequestGenerator() {} virtual void generate(MirandaRequestQueue* q) { } virtual bool isFinished() { return true; } virtual void completed() { } + virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { + SST::SubComponent::serialize_order(ser); + } + + ImplementVirtualSerializable(SST::Miranda::RequestGenerator) + + }; } diff --git a/src/sst/elements/miranda/mirandaMemMgr.h b/src/sst/elements/miranda/mirandaMemMgr.h index 26e811d4ec..afef186394 100644 --- a/src/sst/elements/miranda/mirandaMemMgr.h +++ b/src/sst/elements/miranda/mirandaMemMgr.h @@ -102,7 +102,9 @@ class MirandaMemoryManager { free(pageArr); } // End mapping by 'first' sharer - } + } + + MirandaMemoryManager() = default; uint64_t mapAddress(const uint64_t addrIn) const { if( __builtin_expect(addrIn >= maxMemoryAddress, 0) ) { @@ -128,6 +130,15 @@ class MirandaMemoryManager { return physAddress; } + void serialize_order(SST::Core::Serialization::serializer& ser) { + SST_SER(pageSize); + SST_SER(pageCount); + SST_SER(maxMemoryAddress); + SST_SER(output); + + SST_SER(pageMap); + } + private: uint64_t pageSize; uint64_t pageCount;