Skip to content

Commit

Permalink
* Saving progress
Browse files Browse the repository at this point in the history
Signed-off-by: Pradnya Khalate <[email protected]>
  • Loading branch information
khalatepradnya committed Feb 3, 2025
1 parent 2dd5ae8 commit 0171e26
Show file tree
Hide file tree
Showing 2 changed files with 290 additions and 46 deletions.
282 changes: 237 additions & 45 deletions runtime/common/RecordParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,72 +12,264 @@
#include <string>
#include <vector>

/// REVISIT: Memory management!
namespace cudaq {

struct OutputRecord {
void *buffer;
std::size_t size;
};

enum struct SchemaType { LABELED, ORDERED };
enum struct RecordType { HEADER, METADATA, OUTPUT, START, END };
enum struct OutputType { RESULT, BOOL, INT, DOUBLE };
enum struct ContainerType { ARRAY, TUPLE };

struct ContainerIterator {
ContainerType cTy;
std::size_t cSize = 0;
std::size_t cIndex = 0;
std::size_t remaining = 0;
std::vector<OutputType> types;

void initialize(ContainerType c) {
cTy = c;
cSize = 0;
cIndex = 0;
remaining = 0;
types = {};
}

bool isFull() {
if ((cSize > 0) && (remaining == 0))
return true;
return false;
}
};

struct RecordParser {
private:
bool labelExpected = false;
SchemaType schema = SchemaType::ORDERED;
RecordType currentRecord;
OutputType currentOutput;
bool isInContainer = false;
ContainerIterator containerIt;

template <typename T>
void addPrimitiveRecord(T value) {
results.emplace_back(
OutputRecord{static_cast<void *>(new T(value)), sizeof(T)});
}

template <typename T>
void addArrayRecord(size_t arrSize) {
T *resArr = new T[arrSize];
results.emplace_back(
OutputRecord{static_cast<void *>(resArr), sizeof(T) * arrSize});
}

OutputType extractPrimitiveType(const std::string &label) {
if ('i' == label[0]) {
auto digits = std::stoi(label.substr(1));
if (1 == digits)
return OutputType::BOOL;
return OutputType::INT;
} else if ('f' == label[0])
return OutputType::DOUBLE;
throw std::runtime_error("Unknown datatype in label");
}

std::size_t extractContainerIndex(const std::string &label) {
if (('[' == label[0]) && (']' == label[label.size() - 1]))
return std::stoi(label.substr(1, label.size() - 1));
if ('.' == label[0])
return std::stoi(label.substr(1, label.size() - 1));
throw std::runtime_error("Index not found in label");
}

/// Parse string like "array<3 x i32>"
std::pair<std::size_t, OutputType>
extractArrayInfo(const std::string &label) {
auto isArray = label.find("array");
auto lessThan = label.find('<');
auto greaterThan = label.find('>');
auto x = label.find('x');
if ((isArray == std::string::npos) || (lessThan == std::string::npos) ||
(greaterThan == std::string::npos) || (x == std::string::npos))
throw std::runtime_error("Array label missing keyword");
std::size_t arrSize =
std::stoi(label.substr(lessThan + 1, x - lessThan - 2));
OutputType arrType =
extractPrimitiveType(label.substr(x + 2, greaterThan - x - 2));
return std::make_pair(arrSize, arrType);
}

void prcoessSingleRecord(const std::string &recValue,
const std::string &recLabel) {
if (!recLabel.empty()) {
if (isInContainer)
containerIt.cIndex = extractContainerIndex(recLabel);
else if (extractPrimitiveType(recLabel) != currentOutput)
throw std::runtime_error("Type mismatch in label");
}

switch (currentOutput) {
case OutputType::BOOL: {
bool value;
if ("true" == recValue)
value = true;
else if ("false" == recValue)
value = false;
else
throw std::runtime_error("Invalid boolean value");
if (isInContainer) {
if (SchemaType::ORDERED == schema) {
if (0 == containerIt.cIndex) {
addArrayRecord<bool>(containerIt.cSize);
containerIt.remaining = containerIt.cSize;
}
static_cast<bool *>(results.back().buffer)[containerIt.cIndex++] =
value;
} else if (SchemaType::LABELED == schema) {
static_cast<bool *>(results.back().buffer)[containerIt.cIndex] =
value;
}
containerIt.remaining--;
if (containerIt.isFull())
isInContainer = false;
} else
addPrimitiveRecord<bool>(value);
break;
}
case OutputType::INT: {
if (isInContainer) {
if (SchemaType::ORDERED == schema) {
if (0 == containerIt.cIndex) {
addArrayRecord<int>(containerIt.cSize);
containerIt.remaining = containerIt.cSize;
}
static_cast<int *>(results.back().buffer)[containerIt.cIndex++] =
std::stoi(recValue);
} else if (SchemaType::LABELED == schema) {
static_cast<int *>(results.back().buffer)[containerIt.cIndex] =
std::stoi(recValue);
}
containerIt.remaining--;
if (containerIt.isFull())
isInContainer = false;
} else
addPrimitiveRecord<int>(std::stoi(recValue));
break;
}
case OutputType::DOUBLE: {
addPrimitiveRecord<double>(std::stod(recValue));
break;
}
}
}

public:
std::vector<OutputRecord> results;

std::vector<OutputRecord> parse(const std::string &data) {
std::vector<OutputRecord> results;
std::vector<std::string> lines = cudaq::split(data, '\n');
std::size_t arrSize = 0;
int arrIdx = -1;
if (lines.empty())
return {};

for (auto line : lines) {
std::vector<std::string> entries = cudaq::split(line, '\t');
if (entries.empty())
continue;
if (entries[0] != "OUTPUT")

if ("HEADER" == entries[0])
currentRecord = RecordType::HEADER;
else if ("METADATA" == entries[0])
currentRecord = RecordType::METADATA;
else if ("OUTPUT" == entries[0])
currentRecord = RecordType::OUTPUT;
else if ("START" == entries[0])
currentRecord = RecordType::START;
else if ("END" == entries[0])
currentRecord = RecordType::END;
else
throw std::runtime_error("Invalid data");

/// TODO: Handle labeled records
if ("BOOL" == entries[1]) {
bool value;
if ("true" == entries[2])
value = true;
else if ("false" == entries[2])
value = false;
results.emplace_back(
OutputRecord{static_cast<void *>(new bool(value)), sizeof(bool)});
} else if ("INT" == entries[1]) {
if (0 != arrSize) {
if (0 == arrIdx) {
int *resArr = new int[arrSize];
results.emplace_back(OutputRecord{static_cast<void *>(resArr),
sizeof(int) * arrSize});
}
static_cast<int *>(results.back().buffer)[arrIdx++] =
std::stoi(entries[2]);
if (arrIdx == arrSize) {
arrSize = 0;
arrIdx = -1;
switch (currentRecord) {
case RecordType::HEADER: {
if ("schema_name" == entries[1]) {
if ("labeled" == entries[2])
schema = SchemaType::LABELED;
else if ("ordered" == entries[2])
schema = SchemaType::ORDERED;
else
throw std::runtime_error("Unknown schema type");
}
/// TODO: Check schema version
break;
}
case RecordType::METADATA:
// ignore metadata for now
break;
case RecordType::START:
// indicates start of a shot
break;
case RecordType::END: {
// indicates end of a shot
if (entries.size() < 2)
throw std::runtime_error("Missing shot status");
if ("0" != entries[1])
throw std::runtime_error("Cannot handle unsuccessful shot");
break;
}
case RecordType::OUTPUT: {
if (entries.size() < 3)
throw std::runtime_error("Insufficent data in a record");
if ((schema == SchemaType::LABELED) && (entries.size() != 4))
throw std::runtime_error(
"Unexpected record size for a labeled record");

std::string recType = entries[1];
std::string recValue = entries[2];
std::string recLabel = (entries.size() == 4) ? entries[3] : "";

if ("RESULT" == recType)
throw std::runtime_error("This type is not yet supported");
if ("TUPLE" == recType)
throw std::runtime_error("This type is not yet supported");

if ("ARRAY" == recType) {
isInContainer = true;
containerIt.initialize(ContainerType::ARRAY);
containerIt.cSize = std::stoi(recValue);
if (0 == containerIt.cSize)
throw std::runtime_error("Got empty array");
if (SchemaType::LABELED == schema) {
auto info = extractArrayInfo(recLabel);
if (info.first != containerIt.cSize)
throw std::runtime_error("Array size mismatch in label");
containerIt.remaining = containerIt.cSize;
if (OutputType::INT == info.second)
addArrayRecord<int>(info.first);
else if (OutputType::BOOL == info.second)
addArrayRecord<bool>(info.first);
}
} else
results.emplace_back(
OutputRecord{static_cast<void *>(new int(std::stoi(entries[2]))),
sizeof(int)});
} else if ("FLOAT" == entries[1]) {
results.emplace_back(
OutputRecord{static_cast<void *>(new int(std::stof(entries[2]))),
sizeof(float)});
} else if ("DOUBLE" == entries[1]) {
results.emplace_back(
OutputRecord{static_cast<void *>(new int(std::stod(entries[2]))),
sizeof(double)});
} else if ("ARRAY" == entries[1]) {
arrSize = std::stoi(entries[2]);
if (0 == arrSize)
throw std::runtime_error("Got empty array");
arrIdx = 0;
} else {
if ("BOOL" == recType)
currentOutput = OutputType::BOOL;
else if ("INT" == recType)
currentOutput = OutputType::INT;
else if ("DOUBLE" == recType)
currentOutput = OutputType::DOUBLE;
else
throw std::runtime_error("Invalid data");
prcoessSingleRecord(recValue, recLabel);
}
break;
}
/// TODO: Handle more types
}
default:
throw std::runtime_error("Unknown record type");
}
} // for line
return results;
}
};
Expand Down
54 changes: 53 additions & 1 deletion unittests/output_record/RecordParserTester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ CUDAQ_TEST(ParserTester, checkIntegers) {
EXPECT_EQ(2, *static_cast<int *>(results[2].buffer));
}

CUDAQ_TEST(ParserTester, checkArray) {
CUDAQ_TEST(ParserTester, checkArrayOrdered) {
const std::string log = "OUTPUT\tARRAY\t4\n"
"OUTPUT\tINT\t0\n"
"OUTPUT\tINT\t1\n"
Expand All @@ -45,4 +45,56 @@ CUDAQ_TEST(ParserTester, checkArray) {
got[i] = ptr[i];
EXPECT_EQ(1, got[2]);
EXPECT_EQ(0, got[3]);
}

CUDAQ_TEST(ParserTester, checkArrayLabeled) {
const std::string log = "HEADER\tschema_name\tlabeled\n"
"HEADER\tschema_version\t1.0\n"
"START\n"
"OUTPUT\tARRAY\t3\tarray<3 x i32>\n"
"OUTPUT\tINT\t13\t[0]\n"
"OUTPUT\tINT\t42\t[1]\n"
"OUTPUT\tINT\t61\t[2]\n"
"END\t0";
cudaq::RecordParser parser;
auto results = parser.parse(log);
EXPECT_EQ(1, results.size());
auto count = results[0].size / sizeof(int);
EXPECT_EQ(3, count);
auto *ptr = static_cast<int *>(results[0].buffer);
std::vector<int> got(count);
for (int i = 0; i < count; ++i)
got[i] = ptr[i];
EXPECT_EQ(13, got[0]);
EXPECT_EQ(61, got[2]);
}

CUDAQ_TEST(ParserTester, checkMultipleShots) {
const std::string log = "HEADER\tschema_name\tlabeled\n"
"START\n"
"OUTPUT\tARRAY\t2\tarray<2 x i1>\n"
"OUTPUT\tBOOL\ttrue\t[0]\n"
"OUTPUT\tBOOL\ttrue\t[1]\n"
"END\t0\n"
"START\n"
"OUTPUT\tARRAY\t2\tarray<2 x i1>\n"
"OUTPUT\tBOOL\tfalse\t[1]\n"
"OUTPUT\tBOOL\ttrue\t[0]\n"
"END\t0\n"
"START\n"
"OUTPUT\tARRAY\t2\tarray<2 x i1>\n"
"OUTPUT\tBOOL\ttrue\t[0]\n"
"OUTPUT\tBOOL\tfalse\t[1]\n"
"END\t0";
cudaq::RecordParser parser;
auto results = parser.parse(log);
EXPECT_EQ(3, results.size());
auto count = results[1].size / sizeof(bool);
EXPECT_EQ(2, count);
auto *ptr = static_cast<bool *>(results[1].buffer);
std::vector<bool> got(count);
for (int i = 0; i < count; ++i)
got[i] = ptr[i];
EXPECT_EQ(true, got[0]);
EXPECT_EQ(false, got[1]);
}

0 comments on commit 0171e26

Please sign in to comment.