aboutsummaryrefslogtreecommitdiff
path: root/src/profiler.cpp
blob: 6d4093f8c759dc45822606c0ed409b9a410a2d06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// #define PROF_TIMINGS

struct ProfInfo {
	String  name;
	HashKey hash;
	i32     count;
	i64     total_time;
};

struct Profiler {
	Map<ProfInfo> info; // Key: String
	isize max_name_len;
	i64 start_time;
};

gb_global Profiler global_profiler;

i64 prof_get_timestamp(void) {
	LARGE_INTEGER counter;
	QueryPerformanceCounter(&counter);
	return counter.QuadPart;
}

void prof_init(void) {
#if defined(PROF_TIMINGS)
	map_init(&global_profiler.info, heap_allocator());
	global_profiler.start_time = prof_get_timestamp();
#endif
}




ProfInfo prof_begin(String name) {
	ProfInfo info = {};
	info.name = name;
	info.hash = hash_pointer(name.text); // NOTE(bill): Requires it to be unique

	info.total_time = prof_get_timestamp();
	return info;
}

void prof_end(ProfInfo info) {
	i64 dt = prof_get_timestamp() - info.total_time;
	info.total_time = dt;

	auto *found = map_get(&global_profiler.info, info.hash);
	if (found) {
		found->count++;
		found->total_time += info.total_time;
	} else {
		info.count++;
		map_set(&global_profiler.info, info.hash, info);
		if (global_profiler.max_name_len < info.name.len) {
			global_profiler.max_name_len = info.name.len;
		}
	}
}

struct ScopedProfInfo {
	ProfInfo info;
	ScopedProfInfo(String name) {
		info = prof_begin(name);
	}
	~ScopedProfInfo() {
		prof_end(info);
	}
};

#if defined(PROF_TIMINGS)
#define PROF_SCOPED(msg) ScopedProfInfo scoped_prof_info_##__COUNTER__ = ScopedProfInfo(make_string(cast(u8 *)msg, gb_size_of(msg)-1))
#else
#define PROF_SCOPED(msg) do {} while (0)
#endif
#define PROF_PROC() PROF_SCOPED(__FUNCTION__)

void prof_print_all(void) {
#if defined(PROF_TIMINGS)
	LARGE_INTEGER win32_perf_count_freq = {0};
	QueryPerformanceFrequency(&win32_perf_count_freq);
	GB_ASSERT(win32_perf_count_freq.QuadPart != 0);

	gb_printf("Profiler Timings\n");

	i32 string_offset = cast(int)global_profiler.max_name_len;
	char spaces[]  = "                                                                                ";
	char dashses[] = "--------------------------------------------------------------------------------";
	isize pad_len = gb_size_of(spaces)-1;

	isize info_count = global_profiler.info.entries.count;
	ProfInfo *info_data = gb_alloc_array(heap_allocator(), ProfInfo, info_count);
	defer (gb_free(heap_allocator(), info_data));
	for (isize i = 0; i < info_count; i++) {
		info_data[i] = global_profiler.info.entries[i].value;
	}

	gb_sort_array(info_data, info_count, gb_i64_cmp(gb_offset_of(ProfInfo, total_time)));

	for (isize i = info_count-1; i >= 0; i--) {
		auto entry = info_data + i;
		f64 dt = (1000.0*entry->total_time / cast(f64)win32_perf_count_freq.QuadPart);
		int pad = global_profiler.max_name_len - entry->name.len;
		pad = gb_max(pad, 0);
		gb_printf("%.*s%*.*s - %.3f ms - %.3f us\n",
		          LIT(entry->name),
		          pad, pad, spaces,
		          dt, 1000.0*dt/cast(f64)entry->count);
	}

	i64 total_time = prof_get_timestamp() - global_profiler.start_time;
	f64 total_time_ms = (1000.0*total_time / cast(f64)win32_perf_count_freq.QuadPart);


	gb_printf("%*.*s\n"
	          "%*.*s   %.3f ms\n",
	          global_profiler.max_name_len, global_profiler.max_name_len, dashses,
	          global_profiler.max_name_len, global_profiler.max_name_len, spaces,
	          total_time_ms);
#endif
}