Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/CLI/src/Counters.cpp
2725 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#include "Luau/Counters.h"
3
#include "Luau/CodeGenOptions.h"
4
#include "Luau/DenseHash.h"
5
6
#include "lua.h"
7
8
#include <algorithm>
9
#include <string>
10
#include <vector>
11
12
struct LineCounters
13
{
14
uint64_t regularExecuted = 0;
15
uint64_t fallbackExecuted = 0;
16
uint64_t vmExitTaken = 0;
17
};
18
19
struct FunctionCounters
20
{
21
std::string name;
22
Luau::DenseHashMap<int, LineCounters> counters{-1};
23
};
24
25
struct ModuleCounters
26
{
27
std::string name;
28
std::vector<FunctionCounters> functions;
29
};
30
31
struct Counters
32
{
33
lua_State* L = nullptr;
34
std::vector<int> moduleRefs;
35
36
std::vector<ModuleCounters> moduleCounters;
37
38
} gCounters;
39
40
void countersInit(lua_State* L)
41
{
42
gCounters.L = lua_mainthread(L);
43
}
44
45
bool countersActive()
46
{
47
return gCounters.L != nullptr;
48
}
49
50
void countersTrack(lua_State* L, int funcindex)
51
{
52
int ref = lua_ref(L, funcindex);
53
gCounters.moduleRefs.push_back(ref);
54
}
55
56
static void countersFunctionCallback(void* context, const char* function, int lineDefined)
57
{
58
ModuleCounters& counters = *(ModuleCounters*)context;
59
60
std::string name;
61
62
if (function == nullptr && lineDefined == 1)
63
name = "<main>";
64
else if (function)
65
name = std::string(function) + ":" + std::to_string(lineDefined);
66
else
67
name = "<anonymous>:" + std::to_string(lineDefined);
68
69
counters.functions.emplace_back();
70
counters.functions.back().name = name;
71
}
72
73
static void countersValueCallback(void* context, int kind, int line, uint64_t hits)
74
{
75
ModuleCounters& counters = *(ModuleCounters*)context;
76
FunctionCounters& function = counters.functions.back();
77
78
Luau::CodeGen::CodeGenCounter counterKind = Luau::CodeGen::CodeGenCounter(kind);
79
80
if (counterKind == Luau::CodeGen::CodeGenCounter::RegularBlockExecuted)
81
function.counters[line].regularExecuted += hits;
82
else if (counterKind == Luau::CodeGen::CodeGenCounter::FallbackBlockExecuted)
83
function.counters[line].fallbackExecuted += hits;
84
else if (counterKind == Luau::CodeGen::CodeGenCounter::VmExitTaken)
85
function.counters[line].vmExitTaken += hits;
86
}
87
88
void countersDump(const char* path)
89
{
90
lua_State* L = gCounters.L;
91
92
for (int fref : gCounters.moduleRefs)
93
{
94
lua_getref(L, fref);
95
96
lua_Debug ar = {};
97
lua_getinfo(L, -1, "s", &ar);
98
99
gCounters.moduleCounters.emplace_back();
100
ModuleCounters& moduleCounters = gCounters.moduleCounters.back();
101
102
moduleCounters.name = std::string(ar.short_src);
103
lua_getcounters(L, -1, &moduleCounters, countersFunctionCallback, countersValueCallback);
104
105
lua_pop(L, 1);
106
}
107
108
FILE* f = fopen(path, "wb");
109
if (!f)
110
{
111
fprintf(stderr, "Error opening counters file (callgrind) %s\n", path);
112
return;
113
}
114
115
fprintf(f, "version: 1\n");
116
fprintf(f, "creator: Luau REPL\n");
117
fprintf(f, "events: Regular Fallback VmExit\n");
118
119
for (const ModuleCounters& moduleCounter : gCounters.moduleCounters)
120
{
121
fprintf(f, "fl=%s\n", moduleCounter.name.c_str());
122
123
for (const FunctionCounters& functionCounter : moduleCounter.functions)
124
{
125
fprintf(f, "fn=%s\n", functionCounter.name.c_str());
126
127
// For presentation and stability, we need line counter data sorted by line
128
std::vector<std::pair<int, LineCounters>> sortedCounters;
129
130
for (const auto& [line, counters] : functionCounter.counters)
131
sortedCounters.emplace_back(line, counters);
132
133
std::sort(
134
sortedCounters.begin(),
135
sortedCounters.end(),
136
[](auto&& a, auto&& b)
137
{
138
return a.first < b.first;
139
}
140
);
141
142
for (const auto& [line, counters] : sortedCounters)
143
{
144
if (counters.regularExecuted != 0 || counters.fallbackExecuted != 0 || counters.vmExitTaken != 0)
145
{
146
fprintf(
147
f,
148
"%d %lld %lld %lld\n",
149
line,
150
(long long)counters.regularExecuted,
151
(long long)counters.fallbackExecuted,
152
(long long)counters.vmExitTaken
153
);
154
}
155
}
156
}
157
}
158
159
fclose(f);
160
161
printf("Counters data written to %s (%d modules)\n", path, int(gCounters.moduleCounters.size()));
162
}
163
164