Skip to content

Commit

Permalink
Add line by line perf
Browse files Browse the repository at this point in the history
  • Loading branch information
emilienlemaire committed Jul 26, 2023
1 parent 6b44051 commit 4250dd7
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 3 deletions.
12 changes: 11 additions & 1 deletion cobc/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1793,6 +1793,7 @@ output_standard_includes (struct cb_program *prog)
}
}
output_line ("#include <libcob.h>");
output_line ("#include <libcob/cobperf.h>");
output_newline ();
}

Expand Down Expand Up @@ -5279,6 +5280,10 @@ output_cobol_info (cb_tree x)
}
output ("\"");
output_newline ();
output_line("cobperf_runline(\"%s\", %d, frame_ptr->section_name, frame_ptr->paragraph_name);",
x->source_file,
x->source_line);
output_newline ();
}

static void
Expand Down Expand Up @@ -13251,11 +13256,12 @@ output_entry_function (struct cb_program *prog, cb_tree entry,
}
}

output_line("cobperf_init();");
output_prefix ();
if (prog->flag_void) {
output ("(void)");
} else {
output ("return ");
output ("int res = ");
}
if (!prog->nested_level) {
output ("%s_ (%d", prog->program_id, progid);
Expand Down Expand Up @@ -13303,6 +13309,10 @@ output_entry_function (struct cb_program *prog, cb_tree entry,
}
output (");");
output_newline ();
output_line("cobperf_end();");
if (!prog->flag_void) {
output_line("return res;");
}
output_block_close ();
output_newline ();
}
Expand Down
1 change: 1 addition & 0 deletions cobc/typeck.c
Original file line number Diff line number Diff line change
Expand Up @@ -13970,6 +13970,7 @@ cb_emit_start (cb_tree file, cb_tree op, cb_tree key, cb_tree keylen)
void
cb_emit_stop_run (cb_tree x)
{
cb_emit (CB_BUILD_FUNCALL_0 ("cobperf_end"));
cb_emit (CB_BUILD_FUNCALL_1 ("cob_stop_run", cb_build_cast_int (x)));
}

Expand Down
4 changes: 2 additions & 2 deletions libcob/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
lib_LTLIBRARIES = libcob.la
libcob_la_SOURCES = common.c move.c numeric.c strings.c \
fileio.c call.c intrinsic.c termio.c screenio.c reportio.c cobgetopt.c \
mlio.c coblocal.h cconv.c system.def
mlio.c coblocal.h cconv.c system.def cobperf.c

if LOCAL_CJSON
nodist_libcob_la_SOURCES = cJSON.c
Expand All @@ -42,7 +42,7 @@ libcob_la_LDFLAGS = $(COB_FIX_LIBTOOL) -version-info 6:0:2 -no-undefined
AM_LDFLAGS = $(COB_FIX_LIB)

pkgincludedir = $(includedir)/libcob
pkginclude_HEADERS = common.h version.h cobgetopt.h \
pkginclude_HEADERS = common.h version.h cobgetopt.h cobperf.h \
exception.def exception-io.def statement.def

# Add rules for code-coverage testing, as provided by AX_CODE_COVERAGE
Expand Down
176 changes: 176 additions & 0 deletions libcob/cobperf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
Copyright (C) 2003-2023 Free Software Foundation, Inc.
Written by Emilien Lemaire
This file is part of GnuCOBOL.
The GnuCOBOL compiler is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
GnuCOBOL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GnuCOBOL. If not, see <https://www.gnu.org/licenses/>.
*/

#include "cobperf.h"

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>

struct linedata {
const char *filename;
unsigned line_number;
const char *procedure_name;
const char *paragraph_name;
};

struct rundata {
long long total_time;
unsigned count;
linedata line_data;
};


typedef struct array {
size_t capacity;
size_t size;
void **data;
} array ;

typedef void (*array_callback)(void *data, size_t idx, void *usr);

#define ARRAY_DEFAULT_CAPACITY 128
#define ARRAY_GROW_FACTOR 2

static array *array_init(size_t capacity) {
array *arr = (array*)malloc(sizeof(array));

if (arr == NULL) return arr;

arr->capacity = capacity;
arr->size = 0;
arr->data = calloc(capacity, sizeof(void*));

return arr;
}

static array *array_init_default() {
return array_init(ARRAY_DEFAULT_CAPACITY);
}

static void array_resize(array *arr) {
void **old_data = arr->data;
arr->capacity *= ARRAY_GROW_FACTOR;
arr->data = (void**)calloc(arr->capacity, sizeof(void*));
for (size_t i = 0; i < arr->size; i++) {
arr->data[i] = old_data[i];
}
free(old_data);
}

static void array_push(array* arr, void *data) {
arr->data[arr->size] = data;
arr->size++;
if (arr->size == arr->capacity) {
array_resize(arr);
}
}

static void array_iter(array *arr, array_callback cb, void *usr) {
for (size_t i = 0; i < arr->size; ++i) {
cb(arr->data[i], i, usr);
}
}

static void array_free(array *arr) {
free(arr->data);
free(arr);
}

static array *arr;
struct timespec timestamp;
static linedata *data = NULL;

void cobperf_init() {
arr = array_init_default();
clock_gettime(CLOCK_MONOTONIC, &timestamp);
}

void cobperf_runline(
const char *filename,
unsigned line_number,
const char *procedure_name,
const char *paragraph_name)
{
struct timespec lasttime = timestamp;
clock_gettime(CLOCK_MONOTONIC, &timestamp);
long long timediff = timestamp.tv_nsec - lasttime.tv_nsec;

if (data == NULL) {
data = (linedata*)malloc(sizeof(linedata));
} else {
rundata *run = (rundata*)malloc(sizeof(rundata));
run->count = 1;
run->total_time = timediff;
run->line_data = *data;
array_push(arr, (void *)run);
}
data->filename = filename;
data->line_number = line_number;
data->procedure_name = procedure_name;
data->paragraph_name = paragraph_name;
}

static void run_data_free(void *data, size_t idx, void *_) {
rundata *rdata = (rundata*)data;
free(rdata);
}

static void cobperf_free() {
array_iter(arr, run_data_free, NULL);
array_free(arr);
}

/*todo: aggregate data*/
static void write_rundata_csv(void *data, size_t _, void *file) {
FILE *f = (FILE*)file;
rundata *rdata = (rundata*)data;

fprintf(f, "%s, %s, %s, %u ,%u, %lld\n",
rdata->line_data.filename,
rdata->line_data.procedure_name,
rdata->line_data.paragraph_name,
rdata->line_data.line_number,
rdata->count,
rdata->total_time);
}

void cobperf_end() {
struct timespec lasttime = timestamp;
clock_gettime(CLOCK_MONOTONIC, &timestamp);
long long timediff = timestamp.tv_nsec - lasttime.tv_nsec;

rundata *rdata = (rundata*)malloc(sizeof(rundata));
rdata->count = 1;
rdata->total_time = timediff;
rdata->line_data = *data;
array_push(arr, (void *)rdata);

FILE *f = fopen("prof.csv", "w");
fprintf(f, "Filename, Section, Paragraph, Line, Count, Time\n");
array_iter(arr, write_rundata_csv, (void*)f);
fclose(f);

cobperf_free();
free(data);
}

45 changes: 45 additions & 0 deletions libcob/cobperf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
Copyright (C) 2003-2023 Free Software Foundation, Inc.
Written by Emilien Lemaire
This file is part of GnuCOBOL.
The GnuCOBOL compiler is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
GnuCOBOL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GnuCOBOL. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef cobperf_h
#define cobperf_h

typedef struct linedata linedata;

typedef struct rundata rundata;

void cobperf_init(void);

/**
* Logs a line run.
* @param filename the COBOL filename
* @param line_number the number of the line that runs
* @param section the section name
* @param paragraph the paragraph name
*/
void cobperf_runline(const char *filename, unsigned line_number, const char* section, const char* paragraph);

/**
* This function will save all the logs to the log file.
*/
void cobperf_end(void);

#endif

0 comments on commit 4250dd7

Please sign in to comment.