Skip to content

Commit

Permalink
* Skeleton for output record logging and parsing
Browse files Browse the repository at this point in the history
  -- primitive types
TODO: Handle arrays (vector of results)

Signed-off-by: Pradnya Khalate <[email protected]>
  • Loading branch information
khalatepradnya committed Jan 24, 2025
1 parent 7d70b43 commit cca6e13
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 0 deletions.
69 changes: 69 additions & 0 deletions runtime/common/RecordLogger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/****************************************************************-*- C++ -*-****
* Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. *
* All rights reserved. *
* *
* This source code and the accompanying materials are made available under *
* the terms of the Apache License 2.0 which accompanies this distribution. *
******************************************************************************/

#pragma once

#include <fstream>
#include <sstream>
#include <string>
#include <typeinfo>
#include <vector>

namespace cudaq {

struct RecordLogger {
private:
bool emitLabel = false;
std::stringstream ss;

public:
void emitHeader() {
ss << "HEADER\tschema_name\t" << (emitLabel ? "labeled" : "ordered")
<< "\n";
ss << "HEADER\tschema_version\t1.0\n";
}

template <typename T>
void logSingleRecord(const T &record, std::string label = "") {
if (emitLabel && label.empty())
throw std::runtime_error(
"Non-empty label expected for the output record");

ss << "OUTPUT\t";

if (typeid(T) == typeid(bool)) {
ss << "BOOL\t" << (record ? "true" : "false");
} else if (typeid(T) == typeid(int)) {
ss << "INT\t" << record;
} else if (typeid(T) == typeid(float)) {
ss << "FLOAT\t" << record;
} else if (typeid(T) == typeid(double)) {
ss << "DOUBLE\t" << record;
/// TODO: Handle more types
} else
throw std::runtime_error("Unsupported output record type");

ss << "\n";
}

template <typename T>
void log(const std::vector<T> &records) {
emitHeader();
for (auto r : records) {
ss << "START\n";
logSingleRecord<T>(r);
ss << "END\t0\n"; // Assumes success always
}
}

std::string getLog() { return ss.str(); }

void writeToFile(std::ofstream &outFile) { outFile << ss.rdbuf(); }
};

} // namespace cudaq
64 changes: 64 additions & 0 deletions runtime/common/RecordParser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/****************************************************************-*- C++ -*-****
* Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. *
* All rights reserved. *
* *
* This source code and the accompanying materials are made available under *
* the terms of the Apache License 2.0 which accompanies this distribution. *
******************************************************************************/

#pragma once

#include "cudaq/utils/cudaq_utils.h"
#include <string>
#include <vector>

namespace cudaq {

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

struct RecordParser {
private:
bool labelExpected = false;

public:
std::vector<OutputRecord> parse(const std::string &data) {
std::vector<OutputRecord> results;
std::vector<std::string> lines = cudaq::split(data, '\n');
for (auto line : lines) {
std::vector<std::string> entries = cudaq::split(line, '\t');
/// TODO: Handle labeled records
if (!entries.empty()) {
if (entries[0] == "OUTPUT") {
if ("BOOL" == entries[1]) {
bool value;
if ("true" == entries[2])
value = true;
else if ("false" == entries[2])
value = false;
results.emplace_back(OutputRecord{
reinterpret_cast<void *>(new bool(value)), sizeof(bool)});
} else if ("INT" == entries[1]) {
results.emplace_back(OutputRecord{
reinterpret_cast<void *>(new int(std::stoi(entries[2]))),
sizeof(int)});
} else if ("FLOAT" == entries[1]) {
results.emplace_back(OutputRecord{
reinterpret_cast<void *>(new int(std::stof(entries[2]))),
sizeof(float)});
} else if ("DOUBLE" == entries[1]) {
results.emplace_back(OutputRecord{
reinterpret_cast<void *>(new int(std::stod(entries[2]))),
sizeof(double)});
}
/// TODO: Handle more types
}
}
}
return results;
}
};

} // namespace cudaq
1 change: 1 addition & 0 deletions unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ endif()

add_subdirectory(backends)
add_subdirectory(Optimizer)
add_subdirectory(output_record)

set(CUDAQ_BRAKET_RUNTIME_TEST_SOURCES
# Integration tests
Expand Down
21 changes: 21 additions & 0 deletions unittests/output_record/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# ============================================================================ #
# Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. #
# All rights reserved. #
# #
# This source code and the accompanying materials are made available under #
# the terms of the Apache License 2.0 which accompanies this distribution. #
# ============================================================================ #

add_executable(test_record RecordLoggerTester.cpp RecordParserTester.cpp)

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
target_link_options(test_record PRIVATE -Wl,--no-as-needed)
endif()
target_include_directories(test_record PRIVATE ..)
target_link_libraries(test_record PRIVATE
fmt::fmt-header-only
cudaq-common
gtest_main
)

gtest_discover_tests(test_record)
24 changes: 24 additions & 0 deletions unittests/output_record/RecordLoggerTester.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*******************************************************************************
* Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. *
* All rights reserved. *
* *
* This source code and the accompanying materials are made available under *
* the terms of the Apache License 2.0 which accompanies this distribution. *
******************************************************************************/

#include "CUDAQTestUtils.h"
#include "common/RecordLogger.h"
#include <cudaq.h>

CUDAQ_TEST(LoggerTester, checkBoolean) {
std::vector<bool> results = {true, false, false, true};

const std::string expectedLog =
"HEADER\tschema_name\tordered\nHEADER\tschema_version\t1.0\n"
"START\nOUTPUT\tBOOL\ttrue\nEND\t0\nSTART\nOUTPUT\tBOOL\tfalse\nEND\t0\n"
"START\nOUTPUT\tBOOL\tfalse\nEND\t0\nSTART\nOUTPUT\tBOOL\ttrue\nEND\t0\n";

cudaq::RecordLogger logger;
logger.log(results);
EXPECT_TRUE(expectedLog == logger.getLog());
}
27 changes: 27 additions & 0 deletions unittests/output_record/RecordParserTester.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*******************************************************************************
* Copyright (c) 2022 - 2025 NVIDIA Corporation & Affiliates. *
* All rights reserved. *
* *
* This source code and the accompanying materials are made available under *
* the terms of the Apache License 2.0 which accompanies this distribution. *
******************************************************************************/

#include "CUDAQTestUtils.h"
#include "common/RecordParser.h"
#include <cudaq.h>

CUDAQ_TEST(ParserTester, checkSingleBoolean) {
const std::string log = "OUTPUT\tBOOL\ttrue";
cudaq::RecordParser parser;
auto results = parser.parse(log);
EXPECT_EQ(1, results.size());
}

CUDAQ_TEST(ParserTester, checkIntegers) {
const std::string log = "OUTPUT\tINT\t0\n"
"OUTPUT\tINT\t1\n"
"OUTPUT\tINT\t2\n";
cudaq::RecordParser parser;
auto results = parser.parse(log);
EXPECT_EQ(3, results.size());
}

0 comments on commit cca6e13

Please sign in to comment.