Skip to content
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

use pipe instead of cin and c++ version detection fix #340

Merged
merged 9 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions gpu-simulator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ execute_process(
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND date --iso-8601=minutes
COMMAND date +"%y-%m-%d-%H-%M-%S"
OUTPUT_VARIABLE TIME
OUTPUT_STRIP_TRAILING_WHITESPACE
)

string(REPLACE "\"" "" TIME ${TIME})
set(ACCELSIM_BUILD accelsim-commit-${GIT_COMMIT}_modified_${GIT_FILES_CHANGED_A}${GIT_FILES_CHANGED}_${TIME})

file(WRITE ${CMAKE_BINARY_DIR}/accelsim_version.h "const char *g_accelsim_version=\"${ACCELSIM_BUILD}\";")
Expand Down
2 changes: 1 addition & 1 deletion gpu-simulator/trace-driven/trace_driven.cc
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ void trace_kernel_info_t::get_next_threadblock_traces(
std::vector<std::vector<inst_trace_t> *> threadblock_traces) {
m_parser->get_next_threadblock_traces(
threadblock_traces, m_kernel_trace_info->trace_verion,
m_kernel_trace_info->enable_lineinfo, m_kernel_trace_info->ifs);
m_kernel_trace_info->enable_lineinfo, m_kernel_trace_info->pipeReader);
}

types_of_operands get_oprnd_type(op_type op, special_ops sp_op) {
Expand Down
131 changes: 59 additions & 72 deletions gpu-simulator/trace-parser/trace_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ unsigned inst_trace_t::get_datawidth_from_opcode(
return 4; // default is 4 bytes
}

kernel_trace_t::kernel_trace_t() {
kernel_name = "Empty";
kernel_trace_t::kernel_trace_t(const std::string &filePath)
: pipeReader(filePath) {
kernel_name = filePath;
shmem_base_addr = 0;
local_base_addr = 0;
binary_verion = 0;
Expand Down Expand Up @@ -285,71 +286,12 @@ void trace_parser::parse_memcpy_info(const std::string &memcpy_command,

kernel_trace_t *trace_parser::parse_kernel_info(
const std::string &kerneltraces_filepath) {
kernel_trace_t *kernel_info = new kernel_trace_t;
kernel_info->enable_lineinfo = 0; // default disabled

std::string read_trace_cmd;
int _l = kerneltraces_filepath.length();
if (_l > 3 && kerneltraces_filepath.substr(_l - 3, 3) == ".xz") {
// this is xz-compressed trace
read_trace_cmd = "xz -dc " + kerneltraces_filepath;
} else if (_l > 7 && kerneltraces_filepath.substr(_l - 7, 7) == ".traceg") {
// this is plain text trace
read_trace_cmd = "cat " + kerneltraces_filepath;
} else {
std::cerr << "Can't read trace. Only .xz and plain text are supported: "
<< kerneltraces_filepath << "\n";
exit(1);
}

// Create an interprocess channel, and fork out a data source process. The
// data source process reads trace from disk, write to the channel, and the
// simulator process read from the channel.
int *pipefd = kernel_info->pipefd;
if (pipe(pipefd) != 0) {
std::cerr << "Failed to create interprocess channel\n";
perror("pipe");
exit(1);
}

pid_t pid = fork();
if (pid == 0) {
// The child process is the data source. Redirect its
// stdout to the write end of the pipe.
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);

// When using GDB, sending Ctrl+C to the simulator will send a SIGINT signal
// to the child process as well, subsequently causing it to terminate. To
// avoid this, we let the child process ignore (SIG_IGN) the SIGINT signal.
// Reference:
// https://stackoverflow.com/questions/38404925/gdb-interrupt-running-process-without-killing-child-processes
signal(SIGINT, SIG_IGN);

execle("/bin/sh", "sh", "-c", read_trace_cmd.c_str(), NULL, environ);
perror("execle"); // the child process shouldn't reach here if all is well.
exit(1);
} else {
// parent (simulator)
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
}

// Parent continues from here.
kernel_info->ifs = &std::cin;
std::istream *ifs = kernel_info->ifs;

std::cout << "Processing kernel " << kerneltraces_filepath << std::endl;
kernel_trace_t *kernel_info = new kernel_trace_t(kerneltraces_filepath);
kernel_info->enable_lineinfo = 0; // default disabled

std::string line;

// Important to clear the istream. Otherwise, the eofbit from the last
// kernel may be carried over to this kernel
ifs->clear();
clearerr(stdin);
while (!ifs->eof()) {
getline(*ifs, line);

while (kernel_info->pipeReader.readLine(line)) {
if (line.length() == 0) {
continue;
} else if (line[0] == '#') {
Expand Down Expand Up @@ -421,14 +363,13 @@ void trace_parser::kernel_finalizer(kernel_trace_t *trace_info) {
// have been automatically closed when it terminated. But the parent
// process may read an arbitrary amount of trace files, so it has to close
// all file descriptors.
close(trace_info->pipefd[0]);
close(trace_info->pipefd[1]);
delete trace_info;
}

void trace_parser::get_next_threadblock_traces(
std::vector<std::vector<inst_trace_t> *> threadblock_traces,
unsigned trace_version, unsigned enable_lineinfo, std::istream *ifs) {
unsigned trace_version, unsigned enable_lineinfo,
class PipeReader &pipeReader) {
for (unsigned i = 0; i < threadblock_traces.size(); ++i) {
threadblock_traces[i]->clear();
}
Expand All @@ -439,14 +380,11 @@ void trace_parser::get_next_threadblock_traces(
unsigned warp_id = 0;
unsigned insts_num = 0;
unsigned inst_count = 0;

while (!ifs->eof()) {
std::string line;
std::string line;
while (pipeReader.readLine(line)) {
std::stringstream ss;
std::string string1, string2;

getline(*ifs, line);

if (line.length() == 0) {
continue;
} else {
Expand Down Expand Up @@ -487,3 +425,52 @@ void trace_parser::get_next_threadblock_traces(
}
}
}

PipeReader::PipeReader(const std::string &filePath) { OpenFile(filePath); }

void PipeReader::OpenFile(const std::string &filePath) {
if (hasEnding(filePath, ".xz")) {
// Use xz command to decompress .xz files
command = "xz -dc " + filePath;
} else if (hasEnding(filePath, ".traceg")) {
// Use cat command for regular trace files
command = "cat " + filePath;
} else {
throw std::runtime_error("Unsupported file type!");
}

// Open the pipe
pipe = popen(command.c_str(), "r");
if (!pipe) {
throw std::runtime_error("Failed to open pipe!");
}
}

bool PipeReader::readLine(std::string &line) {
JRPan marked this conversation as resolved.
Show resolved Hide resolved
char *buffer = nullptr;
size_t len = 0;
ssize_t nread;

// Use getline() to read from the pipe
if ((nread = getline(&buffer, &len, pipe)) != -1) {
line.assign(buffer, nread); // Assign the read line to the std::string
assert(line.back() == '\n');
line.pop_back(); // Remove the newline character
free(buffer); // Free the buffer allocated by getline
return true;
}

free(buffer); // Free the buffer if getline failed or reached EOF
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Linux man page for free(3p), no action happens if the argument is a null pointer... Nice job exploiting that characteristic.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

power of chatgpt. Most of this is written by ChatGPT. lol

return false; // End of pipe or error
}

// Helper function to check if a string ends with a specific suffix (file
// extension)
bool PipeReader::hasEnding(const std::string &fullString,
const std::string &ending) {
if (fullString.length() >= ending.length()) {
return (0 == fullString.compare(fullString.length() - ending.length(),
ending.length(), ending));
}
return false;
}
35 changes: 28 additions & 7 deletions gpu-simulator/trace-parser/trace_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,32 @@ struct inst_trace_t {
~inst_trace_t();
};

class PipeReader {
public:
PipeReader(const std::string &filePath);
void OpenFile(const std::string &filePath);
JRPan marked this conversation as resolved.
Show resolved Hide resolved

// Destructor to close the pipe
~PipeReader() {
if (pipe) {
pclose(pipe); // Close the pipe when done
}
}

// Read one line
bool readLine(std::string &line);

private:
FILE *pipe = NULL; // Store the pipe
std::string command; // Store the shell command to be executed

// Helper function to check if a string ends with a specific suffix (file
// extension)
bool hasEnding(const std::string &fullString, const std::string &ending);
};

struct kernel_trace_t {
kernel_trace_t();
kernel_trace_t(const std::string &filePath);

std::string kernel_name;
unsigned kernel_id;
Expand All @@ -95,11 +119,7 @@ struct kernel_trace_t {
std::string nvbit_verion;
unsigned long long shmem_base_addr;
unsigned long long local_base_addr;
// Reference to open filestream
std::istream *ifs;
// Anonymous pipe through which the trace is transmitted from a trace reader
// process to the simulator process
int pipefd[2] = {};
PipeReader pipeReader;
};

class trace_parser {
Expand All @@ -116,7 +136,8 @@ class trace_parser {

void get_next_threadblock_traces(
std::vector<std::vector<inst_trace_t> *> threadblock_traces,
unsigned trace_version, unsigned enable_lineinfo, std::istream *ifs);
unsigned trace_version, unsigned enable_lineinfo,
class PipeReader &pipeReader);

void kernel_finalizer(kernel_trace_t *trace_info);

Expand Down
6 changes: 3 additions & 3 deletions gpu-simulator/version_detection.mk
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ ACCELSIM_VERSION=$(shell cat $(ACCELSIM_ROOT)/version | awk '/Version/ {print $$
GIT_COMMIT := $(shell git log --abbrev-commit -n 1 | head -1 | sed -re 's/commit (.*)/\1/')
GIT_FILES_CHANGED_A:=$(shell git diff --numstat | wc | sed -re 's/^\s+([0-9]+).*/\1./')
GIT_FILES_CHANGED:= $(GIT_FILES_CHANGED_A)$(shell git diff --numstat --cached | wc | sed -re 's/^\s+([0-9]+).*/\1/')
TIME:=$(shell date +"%y-%m-%d-%k-%M-%S")
TIME:=$(shell date +"%y-%m-%d-%H-%M-%S")
ACCELSIM_BUILD := accelsim-commit-$(GIT_COMMIT)_modified_$(GIT_FILES_CHANGED)_$(TIME)
endif

Expand All @@ -43,7 +43,7 @@ CUDA_VERSION_STRING:=$(shell $(CUDA_INSTALL_PATH)/bin/nvcc --version | awk '/rel
CUDART_VERSION:=$(shell echo $(CUDA_VERSION_STRING) | sed 's/\./ /' | awk '{printf("%02u%02u", 10*int($$1), 10*$$2);}')

# Detect GCC Version
CC_VERSION := $(shell gcc --version | head -1 | awk '{for(i=1;i<=NF;i++){ if(match($$i,/^[0-9]\.[0-9]\.[0-9]$$/)) {print $$i; exit 0 }}}')
CC_VERSION := $(shell gcc --version | head -1 | awk '{for(i=1;i<=NF;i++){ if(match($$i,/^[0-9]+\.[0-9]+\.[0-9]+$$/)) {print $$i; exit 0 }}}')

# Detect Support for C++11 (C++0x) from GCC Version
GNUC_CPP0X := $(shell gcc --version | perl -ne 'if (/gcc\s+\(.*\)\s+([0-9.]+)/){ if($$1 >= 4.3) {$$n=1} else {$$n=0;} } END { print $$n; }')
GNUC_CPP0X := 1