From f93f10d1544b1ee18b6ed46e854c0e1a41ddbec6 Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Fri, 20 Jan 2023 14:33:59 +0100 Subject: [PATCH 01/15] reader: Zero object in init and free --- tools/reader.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/reader.c b/tools/reader.c index 17e1e11..1059235 100644 --- a/tools/reader.c +++ b/tools/reader.c @@ -52,15 +52,21 @@ void read_func_list(char* path, RecorderReader *reader) { } void recorder_init_reader(const char* logs_dir, RecorderReader *reader) { - char metadata_file[1024]; + assert(logs_dir); + assert(reader); + + memset(reader, 0, sizeof(*reader)); strcpy(reader->logs_dir, logs_dir); + char metadata_file[1024]; sprintf(metadata_file, "%s/recorder.mt", logs_dir); read_metadata(metadata_file, &reader->metadata); read_func_list(metadata_file, reader); } void recorder_free_reader(RecorderReader *reader) { + assert(reader); + memset(reader, 0, sizeof(*reader)); } const char* recorder_get_func_name(RecorderReader* reader, Record* record) { From 4fa46db653e4d3a0c4e6570a57d10494f89fd5fc Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sat, 21 Jan 2023 22:35:30 +0100 Subject: [PATCH 02/15] reader: Use `logs_dir` member in meta and func_list reader functions No need to pass it as argument, if it is accessible through the `RecorderReader` object. --- tools/reader.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/tools/reader.c b/tools/reader.c index 1059235..60ad775 100644 --- a/tools/reader.c +++ b/tools/reader.c @@ -10,21 +10,28 @@ static int hdf5_start_idx = -1; static double prev_tstart = 0; -void read_metadata(char* path, RecorderMetadata *metadata) { - FILE* fp = fopen(path, "rb"); +void read_metadata(RecorderReader* reader) { + char metadata_file[1024]; + snprintf(metadata_file, sizeof(metadata_file), "%s/recorder.mt", reader->logs_dir); + + FILE* fp = fopen(metadata_file, "rb"); assert(fp != NULL); - fread(metadata, sizeof(RecorderMetadata), 1, fp); + fread(&reader->metadata, sizeof(reader->metadata), 1, fp); fclose(fp); } -void read_func_list(char* path, RecorderReader *reader) { - FILE* fp = fopen(path, "rb"); +void read_func_list(RecorderReader *reader) { + char metadata_file[1024]; + snprintf(metadata_file, sizeof(metadata_file), "%s/recorder.mt", reader->logs_dir); + + FILE* fp = fopen(metadata_file, "rb"); + assert(fp != NULL); fseek(fp, 0, SEEK_END); - long fsize = ftell(fp) - sizeof(RecorderMetadata); + long fsize = ftell(fp) - sizeof(reader->metadata); char buf[fsize]; - fseek(fp, sizeof(RecorderMetadata), SEEK_SET); // skip RecorderMetadata object + fseek(fp, sizeof(reader->metadata), SEEK_SET); // skip RecorderMetadata object fread(buf, 1, fsize, fp); int start_pos = 0, end_pos = 0; @@ -58,10 +65,8 @@ void recorder_init_reader(const char* logs_dir, RecorderReader *reader) { memset(reader, 0, sizeof(*reader)); strcpy(reader->logs_dir, logs_dir); - char metadata_file[1024]; - sprintf(metadata_file, "%s/recorder.mt", logs_dir); - read_metadata(metadata_file, &reader->metadata); - read_func_list(metadata_file, reader); + read_metadata(reader); + read_func_list(reader); } void recorder_free_reader(RecorderReader *reader) { From 093004b2240c3a1c84c22631e4e439bed8e341f3 Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sat, 21 Jan 2023 22:38:48 +0100 Subject: [PATCH 03/15] reader: Merge reading meta data and function list --- tools/reader.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/tools/reader.c b/tools/reader.c index 60ad775..250502c 100644 --- a/tools/reader.c +++ b/tools/reader.c @@ -17,21 +17,13 @@ void read_metadata(RecorderReader* reader) { FILE* fp = fopen(metadata_file, "rb"); assert(fp != NULL); fread(&reader->metadata, sizeof(reader->metadata), 1, fp); - fclose(fp); -} - -void read_func_list(RecorderReader *reader) { - char metadata_file[1024]; - snprintf(metadata_file, sizeof(metadata_file), "%s/recorder.mt", reader->logs_dir); - - FILE* fp = fopen(metadata_file, "rb"); - assert(fp != NULL); + long pos = ftell(fp); fseek(fp, 0, SEEK_END); - long fsize = ftell(fp) - sizeof(reader->metadata); + long fsize = ftell(fp) - pos; char buf[fsize]; - fseek(fp, sizeof(reader->metadata), SEEK_SET); // skip RecorderMetadata object + fseek(fp, pos, SEEK_SET); fread(buf, 1, fsize, fp); int start_pos = 0, end_pos = 0; @@ -66,7 +58,6 @@ void recorder_init_reader(const char* logs_dir, RecorderReader *reader) { strcpy(reader->logs_dir, logs_dir); read_metadata(reader); - read_func_list(reader); } void recorder_free_reader(RecorderReader *reader) { From a62830b67e4f3bf57c3a60aec75b1d3a297e29b6 Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sat, 21 Jan 2023 22:42:01 +0100 Subject: [PATCH 04/15] reader: Move global state into reader object --- tools/reader.c | 28 +++++++++++++--------------- tools/reader.h | 5 +++++ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/tools/reader.c b/tools/reader.c index 250502c..ba64ad7 100644 --- a/tools/reader.c +++ b/tools/reader.c @@ -5,11 +5,6 @@ #include #include "./reader.h" -static int mpi_start_idx = -1; -static int hdf5_start_idx = -1; - -static double prev_tstart = 0; - void read_metadata(RecorderReader* reader) { char metadata_file[1024]; snprintf(metadata_file, sizeof(metadata_file), "%s/recorder.mt", reader->logs_dir); @@ -34,14 +29,14 @@ void read_metadata(RecorderReader* reader) { memset(reader->func_list[func_id], 0, sizeof(reader->func_list[func_id])); memcpy(reader->func_list[func_id], buf+start_pos, end_pos-start_pos); start_pos = end_pos+1; - if((mpi_start_idx==-1) && + if((reader->mpi_start_idx==-1) && (NULL!=strstr(reader->func_list[func_id], "MPI"))) - mpi_start_idx = func_id; + reader->mpi_start_idx = func_id; - if((hdf5_start_idx==-1) && + if((reader->hdf5_start_idx==-1) && (NULL!=strstr(reader->func_list[func_id], "H5"))) - hdf5_start_idx = func_id; + reader->hdf5_start_idx = func_id; func_id++; } @@ -56,6 +51,9 @@ void recorder_init_reader(const char* logs_dir, RecorderReader *reader) { memset(reader, 0, sizeof(*reader)); strcpy(reader->logs_dir, logs_dir); + reader->mpi_start_idx = -1; + reader->hdf5_start_idx = -1; + reader->prev_tstart = 0.0; read_metadata(reader); } @@ -72,9 +70,9 @@ const char* recorder_get_func_name(RecorderReader* reader, Record* record) { } int recorder_get_func_type(RecorderReader* reader, Record* record) { - if(record->func_id < mpi_start_idx) + if(record->func_id < reader->mpi_start_idx) return RECORDER_POSIX; - if(record->func_id < hdf5_start_idx) { + if(record->func_id < reader->hdf5_start_idx) { const char* func_name = recorder_get_func_name(reader, record); if(strncmp(func_name, "MPI_File", 8) == 0) return RECORDER_MPIIO; @@ -241,9 +239,9 @@ void rule_application(RecorderReader* reader, RuleHash* rules, int rule_id, Call // Fill in timestamps uint32_t ts[2]; fread(ts, sizeof(uint32_t), 2, ts_file); - record->tstart = ts[0] * reader->metadata.time_resolution + prev_tstart; - record->tend = ts[1] * reader->metadata.time_resolution + prev_tstart; - prev_tstart = record->tstart; + record->tstart = ts[0] * reader->metadata.time_resolution + reader->prev_tstart; + record->tend = ts[1] * reader->metadata.time_resolution + reader->prev_tstart; + reader->prev_tstart = record->tstart; user_op(record, user_arg); @@ -265,7 +263,7 @@ void recorder_decode_records_core(RecorderReader *reader, CST *cst, CFG *cfg, assert(cst->rank == cfg->rank); - prev_tstart = 0; + reader->prev_tstart = 0.0; char ts_filename[1096] = {0}; sprintf(ts_filename, "%s/%d.ts", reader->logs_dir, cst->rank); diff --git a/tools/reader.h b/tools/reader.h index 6144d46..a609074 100644 --- a/tools/reader.h +++ b/tools/reader.h @@ -19,6 +19,11 @@ typedef struct RecorderReader_t { char func_list[256][64]; char logs_dir[1024]; + + int mpi_start_idx; + int hdf5_start_idx; + + double prev_tstart; } RecorderReader; typedef struct Interval_t { From e5fecc4f4bc5ec8d01360e33052daff253c3db37 Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sat, 21 Jan 2023 22:43:02 +0100 Subject: [PATCH 05/15] reader: Check `VERSION` file --- tools/reader.c | 18 ++++++++++++++++++ tools/reader.h | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/tools/reader.c b/tools/reader.c index ba64ad7..fb4714b 100644 --- a/tools/reader.c +++ b/tools/reader.c @@ -5,6 +5,22 @@ #include #include "./reader.h" +void check_version(RecorderReader* reader) { + char version_file[1024]; + snprintf(version_file, sizeof(version_file), "%s/VERSION", reader->logs_dir); + + FILE* fp = fopen(version_file, "r"); + assert(fp != NULL); + int major, minor, patch; + fscanf(fp, "%d.%d.%d", &major, &minor, &patch); + if(major != VERSION_MAJOR || minor != VERSION_MINOR) { + fprintf(stderr, "incompatible version: file=%d.%d.%d != reader=%d.%d.%d\n", + major, minor, patch, VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH); + exit(1); + } + fclose(fp); +} + void read_metadata(RecorderReader* reader) { char metadata_file[1024]; snprintf(metadata_file, sizeof(metadata_file), "%s/recorder.mt", reader->logs_dir); @@ -55,6 +71,8 @@ void recorder_init_reader(const char* logs_dir, RecorderReader *reader) { reader->hdf5_start_idx = -1; reader->prev_tstart = 0.0; + check_version(reader); + read_metadata(reader); } diff --git a/tools/reader.h b/tools/reader.h index a609074..0f398ed 100644 --- a/tools/reader.h +++ b/tools/reader.h @@ -3,6 +3,11 @@ #include #include "recorder-logger.h" +// keep in sync with VERSION_STR in lib/recorder-logger.c +// equal (major, minor) is needed for compatibility +#define VERSION_MAJOR 2 +#define VERSION_MINOR 3 +#define VERSION_PATCH 3 #define POSIX_SEMANTICS 0 #define COMMIT_SEMANTICS 1 From b8165148e1e9e46517c327175d271c74c6b665ff Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sat, 21 Jan 2023 22:28:05 +0100 Subject: [PATCH 06/15] Prefer `gettid` over `pthread_self` `pthread_self` returns a pointer value, which has no correlation to any OS object. Hence use `gettid` if available. --- include/recorder-utils.h | 2 ++ include/recorder.h | 2 +- lib/recorder-cuda-profiler.c | 2 +- lib/recorder-function-profiler.c | 4 ++-- lib/recorder-utils.c | 12 +++++++++++- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/include/recorder-utils.h b/include/recorder-utils.h index 19fbf03..1ccc10e 100644 --- a/include/recorder-utils.h +++ b/include/recorder-utils.h @@ -2,11 +2,13 @@ #define _RECORDER_UTILS_H_ #include +#include void utils_init(); void utils_finalize(); void* recorder_malloc(size_t size); void recorder_free(void* ptr, size_t size); +pthread_t recorder_gettid(void); long get_file_size(const char *filename); // return the size of a file int accept_filename(const char *filename); // if include the file in trace double recorder_wtime(void); // return the timestamp diff --git a/include/recorder.h b/include/recorder.h index 4d7f871..4062ebf 100644 --- a/include/recorder.h +++ b/include/recorder.h @@ -163,7 +163,7 @@ \ Record *record = recorder_malloc(sizeof(Record)); \ record->func_id = get_function_id_by_name(#func); \ - record->tid = pthread_self(); \ + record->tid = recorder_gettid(); \ logger_record_enter(record); \ record->tstart = recorder_wtime(); \ ret res = RECORDER_REAL_CALL(func) real_args ; \ diff --git a/lib/recorder-cuda-profiler.c b/lib/recorder-cuda-profiler.c index 8de84b1..03a17f0 100644 --- a/lib/recorder-cuda-profiler.c +++ b/lib/recorder-cuda-profiler.c @@ -134,7 +134,7 @@ Record* create_recorder_record(CUpti_ActivityKernel5 *kernel) { Record *record = recorder_malloc(sizeof(Record)); record->func_id = RECORDER_USER_FUNCTION; record->level = 0; - record->tid = pthread_self(); + record->tid = recorder_gettid(); record->tstart = (kernel->start - startTimestamp)/10e9; record->tstart = (kernel->end - startTimestamp)/10e9; record->arg_count = 2; diff --git a/lib/recorder-function-profiler.c b/lib/recorder-function-profiler.c index 02712ad..6bb18dc 100644 --- a/lib/recorder-function-profiler.c +++ b/lib/recorder-function-profiler.c @@ -25,7 +25,7 @@ func_hash_t* func_table; void* compose_func_hash_key(void* func, int *key_len) { - pthread_t tid = pthread_self(); + pthread_t tid = recorder_gettid(); *key_len = sizeof(pthread_t) + sizeof(void*); void* key = recorder_malloc(*key_len); memcpy(key, &tid, sizeof(pthread_t)); @@ -89,7 +89,7 @@ void __cyg_profile_func_exit (void *func, void *caller) Record *record = recorder_malloc(sizeof(Record)); record->func_id = RECORDER_USER_FUNCTION; record->level = 0; - record->tid = pthread_self(); + record->tid = recorder_gettid(); record->tstart = entry->tstart_head->tstart; record->tend = recorder_wtime(); record->arg_count = 2; diff --git a/lib/recorder-utils.c b/lib/recorder-utils.c index 9f4a060..d5f2bc0 100644 --- a/lib/recorder-utils.c +++ b/lib/recorder-utils.c @@ -1,13 +1,14 @@ #define _GNU_SOURCE +#include #include // for gettimeofday() #include // for va_list, va_start and va_end +#include // for SYS_gettid #include #include #include #include "recorder.h" #include "recorder-utils.h" - // Log pointer addresses in the trace file? static bool log_pointer = false; static size_t memory_usage = 0; @@ -169,6 +170,15 @@ inline int accept_filename(const char *filename) { return 1; } +inline pthread_t recorder_gettid(void) +{ +#ifdef SYS_gettid + return syscall(SYS_gettid); +#else + return pthread_self(); +#endif +} + inline long get_file_size(const char *filename) { struct stat sb; int res = stat(filename, &sb); // careful here, make sure stat() is not intercepted From f01ee0e0a35a631c997ddea5779f4eb58f971a7b Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sat, 21 Jan 2023 22:29:14 +0100 Subject: [PATCH 07/15] timeline: Remove unused code --- tools/recorder2timeline.cpp | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/tools/recorder2timeline.cpp b/tools/recorder2timeline.cpp index 303b313..f896960 100644 --- a/tools/recorder2timeline.cpp +++ b/tools/recorder2timeline.cpp @@ -9,8 +9,7 @@ #include #include #include -static int do_mutex; -static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + RecorderReader reader; struct Writer{ @@ -54,28 +53,6 @@ void write_to_json(Record *record, void* arg) { int min(int a, int b) { return a < b ? a : b; } int max(int a, int b) { return a > b ? a : b; } -static void * execute(void * global_writer) { - Writer* writer = (Writer*)global_writer; - int n = max(reader.metadata.total_ranks/writer->total_ranks, 1); - int start_rank = n * writer->my_rank; - int end_rank = min(reader.metadata.total_ranks, n*(writer->my_rank+1)); - Writer local; - local.outFile.open(writer->filename,std::ofstream::out| std::ofstream::app); - for(int rank = start_rank; rank < end_rank; rank++) { - CST cst; - CFG cfg; - local.rank = rank; - recorder_read_cst(&reader, rank, &cst); - recorder_read_cfg(&reader, rank, &cfg); - recorder_decode_records(&reader, &cst, &cfg, write_to_json, &local); - printf("\r[Recorder] rank %d finished, unique call signatures: %d\n", rank, cst.entries); - recorder_free_cst(&cst); - recorder_free_cfg(&cfg); - } - local.outFile.close(); - return NULL; -} - int main(int argc, char **argv) { char textfile_dir[256]; From b1e856c915f682d84d7205e5b646120efb9ced2d Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sun, 22 Jan 2023 12:46:26 +0100 Subject: [PATCH 08/15] timeline: Fix style --- tools/recorder2timeline.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/recorder2timeline.cpp b/tools/recorder2timeline.cpp index f896960..563a8c1 100644 --- a/tools/recorder2timeline.cpp +++ b/tools/recorder2timeline.cpp @@ -37,15 +37,15 @@ void write_to_json(Record *record, void* arg) { << ",\"tid\":" << cat << ",\"ts\":" << ts << ",\"name\":\"" << func_name - << "\",\"cat\":\"" << cat; - ss << "\",\"ph\":\"X\""<< "" - << ",\"dur\":" << dur; - ss <<",\"args\":\""; + << "\",\"cat\":\"" << cat + << "\",\"ph\":\"X\"" + << ",\"dur\":" << dur + << ",\"args\":\""; for (int arg_id = 0; !user_func && arg_id < record->arg_count; arg_id++) { char *arg = record->args[arg_id]; ss << " " << arg; } - ss << " tend: "<< record->tend <<"\"},\n"; + ss << " tend: " << record->tend << "\"},\n"; writer->outFile << ss.rdbuf(); } } From de59d959f78ded008ff17448958c76eea1af6e4d Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sun, 22 Jan 2023 11:05:26 +0100 Subject: [PATCH 09/15] timeline: Do not init reader twice --- tools/recorder2timeline.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/recorder2timeline.cpp b/tools/recorder2timeline.cpp index 563a8c1..d78b1e4 100644 --- a/tools/recorder2timeline.cpp +++ b/tools/recorder2timeline.cpp @@ -55,24 +55,25 @@ int max(int a, int b) { return a > b ? a : b; } int main(int argc, char **argv) { - char textfile_dir[256]; - char textfile_path[256]; - sprintf(textfile_dir, "%s/_chrome", argv[1]); - recorder_init_reader(argv[1], &reader); int mpi_size, mpi_rank; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + char textfile_dir[256]; + sprintf(textfile_dir, "%s/_chrome", argv[1]); + if(mpi_rank == 0) mkdir(textfile_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); MPI_Barrier(MPI_COMM_WORLD); + recorder_init_reader(argv[1], &reader); // Each rank will process n files (n ranks traces) int n = max(reader.metadata.total_ranks/mpi_size, 1); int start_rank = n * mpi_rank; int end_rank = min(reader.metadata.total_ranks, n*(mpi_rank+1)); + char textfile_path[256]; sprintf(textfile_path, "%s/timeline_%d.json", textfile_dir, mpi_rank); Writer local; local.outFile.open(textfile_path, std::ofstream::trunc|std::ofstream::out); From 4111b69a55a8912d1860929791e8d23f87c0ee19 Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Fri, 20 Jan 2023 14:34:10 +0100 Subject: [PATCH 10/15] timeline: Basic usage message --- tools/recorder2timeline.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/recorder2timeline.cpp b/tools/recorder2timeline.cpp index d78b1e4..2699e98 100644 --- a/tools/recorder2timeline.cpp +++ b/tools/recorder2timeline.cpp @@ -9,6 +9,7 @@ #include #include #include +#include RecorderReader reader; @@ -55,6 +56,11 @@ int max(int a, int b) { return a > b ? a : b; } int main(int argc, char **argv) { + if(argc!=2) { + std::cerr << "Usage: " << argv[0] << " \n"; + std::exit(1); + } + int mpi_size, mpi_rank; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); From 391c019c08f3548b18d03c156a47443332c0e55c Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sat, 21 Jan 2023 22:29:33 +0100 Subject: [PATCH 11/15] timeline: Do not use the category for the tid --- tools/recorder2timeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/recorder2timeline.cpp b/tools/recorder2timeline.cpp index 2699e98..281fdd5 100644 --- a/tools/recorder2timeline.cpp +++ b/tools/recorder2timeline.cpp @@ -35,7 +35,7 @@ void write_to_json(Record *record, void* arg) { if (dur <= 0) dur = 0; std::stringstream ss; ss << "{\"pid\":" << writer->rank - << ",\"tid\":" << cat + << ",\"tid\":" << tid << ",\"ts\":" << ts << ",\"name\":\"" << func_name << "\",\"cat\":\"" << cat From 3546f20bb23b6b5c2a06d216c43ecf310c98c653 Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sat, 21 Jan 2023 22:30:13 +0100 Subject: [PATCH 12/15] timeline: Resolve function type to readable name --- tools/recorder2timeline.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/recorder2timeline.cpp b/tools/recorder2timeline.cpp index 281fdd5..38ca2e6 100644 --- a/tools/recorder2timeline.cpp +++ b/tools/recorder2timeline.cpp @@ -19,6 +19,21 @@ struct Writer{ int rank, my_rank, total_ranks; }; +static const char* type_name(int type) { + switch (type) { + case RECORDER_POSIX: + return "POSIX"; + case RECORDER_MPIIO: + return "MPI I/O"; + case RECORDER_MPI: + return "MPI"; + case RECORDER_HDF5: + return "HDF5"; + case RECORDER_FTRACE: + return "USER"; + } +} + void write_to_json(Record *record, void* arg) { int cat = recorder_get_func_type(&reader, record); @@ -38,7 +53,7 @@ void write_to_json(Record *record, void* arg) { << ",\"tid\":" << tid << ",\"ts\":" << ts << ",\"name\":\"" << func_name - << "\",\"cat\":\"" << cat + << "\",\"cat\":\"" << type_name(cat) << "\",\"ph\":\"X\"" << ",\"dur\":" << dur << ",\"args\":\""; From 126d3ee70c0c66f3c54790592bf5e63429f8c5ec Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sat, 21 Jan 2023 22:49:59 +0100 Subject: [PATCH 13/15] timeline: Produce valid JSON No trailing comma in array. --- tools/recorder2timeline.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/recorder2timeline.cpp b/tools/recorder2timeline.cpp index 38ca2e6..49730a9 100644 --- a/tools/recorder2timeline.cpp +++ b/tools/recorder2timeline.cpp @@ -15,7 +15,7 @@ RecorderReader reader; struct Writer{ std::ofstream outFile; - char* filename; + const char* sep; int rank, my_rank, total_ranks; }; @@ -49,7 +49,8 @@ void write_to_json(Record *record, void* arg) { uint64_t dur = uint64_t((record->tend - record->tstart) / reader.metadata.time_resolution); if (dur <= 0) dur = 0; std::stringstream ss; - ss << "{\"pid\":" << writer->rank + ss << writer->sep + << "{\"pid\":" << writer->rank << ",\"tid\":" << tid << ",\"ts\":" << ts << ",\"name\":\"" << func_name @@ -61,8 +62,9 @@ void write_to_json(Record *record, void* arg) { char *arg = record->args[arg_id]; ss << " " << arg; } - ss << " tend: " << record->tend << "\"},\n"; + ss << " tend: " << record->tend << "\"}"; writer->outFile << ss.rdbuf(); + writer->sep = ",\n"; } } @@ -98,7 +100,8 @@ int main(int argc, char **argv) { sprintf(textfile_path, "%s/timeline_%d.json", textfile_dir, mpi_rank); Writer local; local.outFile.open(textfile_path, std::ofstream::trunc|std::ofstream::out); - local.outFile << "{\"traceEvents\": ["; + local.outFile << "{\"traceEvents\": [\n"; + local.sep = ""; for(int rank = start_rank; rank < end_rank; rank++) { CST cst; CFG cfg; @@ -110,7 +113,7 @@ int main(int argc, char **argv) { recorder_free_cst(&cst); recorder_free_cfg(&cfg); } - local.outFile << "],\"displayTimeUnit\": \"ms\",\"systemTraceEvents\": \"SystemTraceData\",\"otherData\": {\"version\": \"Taxonomy v1.0\" }, \"stackFrames\": {}, \"samples\": []}"; + local.outFile << "],\n\"displayTimeUnit\": \"ms\",\"systemTraceEvents\": \"SystemTraceData\",\"otherData\": {\"version\": \"Taxonomy v1.0\" }, \"stackFrames\": {}, \"samples\": []}\n"; local.outFile.close(); recorder_free_reader(&reader); From b0a3bf426dfda57058fc8697cc9a3279cf3c0b82 Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sat, 21 Jan 2023 22:50:22 +0100 Subject: [PATCH 14/15] timeline: Use dict and array for event arguments --- tools/recorder2timeline.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tools/recorder2timeline.cpp b/tools/recorder2timeline.cpp index 49730a9..dd667a4 100644 --- a/tools/recorder2timeline.cpp +++ b/tools/recorder2timeline.cpp @@ -57,12 +57,18 @@ void write_to_json(Record *record, void* arg) { << "\",\"cat\":\"" << type_name(cat) << "\",\"ph\":\"X\"" << ",\"dur\":" << dur - << ",\"args\":\""; - for (int arg_id = 0; !user_func && arg_id < record->arg_count; arg_id++) { - char *arg = record->args[arg_id]; - ss << " " << arg; + << ",\"args\":{"; + if (!user_func) { + ss << "\"args\":["; + const char* sep = ""; + for (int arg_id = 0; arg_id < record->arg_count; arg_id++) { + char *arg = record->args[arg_id]; + ss << sep << "\"" << arg << "\""; + sep = ","; + } + ss << "],"; } - ss << " tend: " << record->tend << "\"}"; + ss << "\"tend\": \"" << record->tend << "\"}}"; writer->outFile << ss.rdbuf(); writer->sep = ",\n"; } From 124dd07cf069cb7d9cde07acae1f4422f0361a0a Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Sun, 22 Jan 2023 12:46:54 +0100 Subject: [PATCH 15/15] timeline: Correct timestamps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current timestamps are 10× larger than expected. Timestamps from Recorder are in seconds and are converted with the timer resolution of the file. Which defaults to 1e-7. Chrome traces expect microseconds as timestamp, optional with a nanosecond fraction. Ignore timer resolution from Recorder and just convert to microseconds and format them as double with precision 3. --- tools/recorder2timeline.cpp | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/tools/recorder2timeline.cpp b/tools/recorder2timeline.cpp index dd667a4..8677dc6 100644 --- a/tools/recorder2timeline.cpp +++ b/tools/recorder2timeline.cpp @@ -10,6 +10,7 @@ #include #include #include +#include RecorderReader reader; @@ -34,6 +35,25 @@ static const char* type_name(int type) { } } +struct timeline_ts{ + double value; +}; +std::ostream& +operator<<( std::ostream& out, + const timeline_ts& ts ) +{ + std::ios oldState(nullptr); + oldState.copyfmt(out); + + // Chrome traces are always in micro seconds and Recorder timestamps in + // seconds. No need to use the timer resolution from the trace to convert + // to microseconds. + out << std::fixed << std::setw(5) << std::setprecision(3) << (ts.value * 1e6); + out.copyfmt(oldState); + + return out; +} + void write_to_json(Record *record, void* arg) { int cat = recorder_get_func_type(&reader, record); @@ -44,19 +64,15 @@ void write_to_json(Record *record, void* arg) { if (user_func) func_name = record->args[0]; - uint64_t ts = uint64_t(record->tstart / reader.metadata.time_resolution); - int tid = record->tid; - uint64_t dur = uint64_t((record->tend - record->tstart) / reader.metadata.time_resolution); - if (dur <= 0) dur = 0; std::stringstream ss; ss << writer->sep << "{\"pid\":" << writer->rank - << ",\"tid\":" << tid - << ",\"ts\":" << ts + << ",\"tid\":" << record->tid + << ",\"ts\":" << timeline_ts{record->tstart} << ",\"name\":\"" << func_name << "\",\"cat\":\"" << type_name(cat) << "\",\"ph\":\"X\"" - << ",\"dur\":" << dur + << ",\"dur\":" << timeline_ts{record->tend - record->tstart} << ",\"args\":{"; if (!user_func) { ss << "\"args\":[";