aboutsummaryrefslogtreecommitdiff
path: root/src/profiler.cpp
blob: d05b7abfe36cafb0f5425d49c552969f7e7dec90 (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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
Minetest
Copyright (C) 2015 celeron55, Perttu Ahola <celeron55@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "profiler.h"
#include "porting.h"

static Profiler main_profiler;
Profiler *g_profiler = &main_profiler;
ScopeProfiler::ScopeProfiler(
		Profiler *profiler, const std::string &name, ScopeProfilerType type) :
		m_profiler(profiler),
		m_name(name), m_type(type)
{
	m_name.append(" [ms]");
	if (m_profiler)
		m_timer = new TimeTaker(m_name, nullptr, PRECISION_MILLI);
}

ScopeProfiler::~ScopeProfiler()
{
	if (!m_timer)
		return;

	float duration_ms = m_timer->stop(true);
	float duration = duration_ms;
	if (m_profiler) {
		switch (m_type) {
		case SPT_ADD:
			m_profiler->add(m_name, duration);
			break;
		case SPT_AVG:
			m_profiler->avg(m_name, duration);
			break;
		case SPT_GRAPH_ADD:
			m_profiler->graphAdd(m_name, duration);
			break;
		}
	}
	delete m_timer;
}

Profiler::Profiler()
{
	m_start_time = porting::getTimeMs();
}

void Profiler::add(const std::string &name, float value)
{
	MutexAutoLock lock(m_mutex);
	{
		/* No average shall have been used; mark add used as -2 */
		std::map<std::string, int>::iterator n = m_avgcounts.find(name);
		if (n == m_avgcounts.end()) {
			m_avgcounts[name] = -2;
		} else {
			if (n->second == -1)
				n->second = -2;
			assert(n->second == -2);
		}
	}
	{
		std::map<std::string, float>::iterator n = m_data.find(name);
		if (n == m_data.end())
			m_data[name] = value;
		else
			n->second += value;
	}
}

void Profiler::avg(const std::string &name, float value)
{
	MutexAutoLock lock(m_mutex);
	int &count = m_avgcounts[name];

	assert(count != -2);
	count = MYMAX(count, 0) + 1;
	m_data[name] += value;
}

void Profiler::clear()
{
	MutexAutoLock lock(m_mutex);
	for (auto &it : m_data) {
		it.second = 0;
	}
	m_avgcounts.clear();
	m_start_time = porting::getTimeMs();
}

float Profiler::getValue(const std::string &name) const
{
	auto numerator = m_data.find(name);
	if (numerator == m_data.end())
		return 0.f;

	auto denominator = m_avgcounts.find(name);
	if (denominator != m_avgcounts.end()) {
		if (denominator->second >= 1)
			return numerator->second / denominator->second;
	}

	return numerator->second;
}

int Profiler::getAvgCount(const std::string &name) const
{
	auto n = m_avgcounts.find(name);

	if (n != m_avgcounts.end() && n->second >= 1)
		return n->second;

	return 1;
}

u64 Profiler::getElapsedMs() const
{
	return porting::getTimeMs() - m_start_time;
}

int Profiler::print(std::ostream &o, u32 page, u32 pagecount)
{
	GraphValues values;
	getPage(values, page, pagecount);
	char num_buf[50];

	for (const auto &i : values) {
		o << "  " << i.first << " ";
		if (i.second == 0) {
			o << std::endl;
			continue;
		}

		s32 space = 44 - i.first.size();
		for (s32 j = 0; j < space; j++) {
			if ((j & 1) && j < space - 1)
				o << ".";
			else
				o << " ";
		}
		porting::mt_snprintf(num_buf, sizeof(num_buf), "% 4ix % 3g",
				getAvgCount(i.first), i.second);
		o << num_buf << std::endl;
	}
	return values.size();
}

void Profiler::getPage(GraphValues &o, u32 page, u32 pagecount)
{
	MutexAutoLock lock(m_mutex);

	u32 minindex, maxindex;
	paging(m_data.size(), page, pagecount, minindex, maxindex);

	for (const auto &i : m_data) {
		if (maxindex == 0)
			break;
		maxindex--;

		if (minindex != 0) {
			minindex--;
			continue;
		}

		o[i.first] = i.second / getAvgCount(i.first);
	}
}
pan>m_sound_manager = nullptr; /** representation of form source to be used in mainmenu formspec */ FormspecFormSource *m_formspecgui = nullptr; /** formspec input receiver */ TextDestGuiEngine *m_buttonhandler = nullptr; /** the formspec menu */ GUIFormSpecMenu *m_menu = nullptr; /** reference to kill variable managed by SIGINT handler */ bool &m_kill; /** variable used to abort menu and return back to main game handling */ bool m_startgame = false; /** scripting interface */ MainMenuScripting *m_script = nullptr; /** script basefolder */ std::string m_scriptdir = ""; /** * draw background layer * @param driver to use for drawing */ void drawBackground(video::IVideoDriver *driver); /** * draw overlay layer * @param driver to use for drawing */ void drawOverlay(video::IVideoDriver *driver); /** * draw header layer * @param driver to use for drawing */ void drawHeader(video::IVideoDriver *driver); /** * draw footer layer * @param driver to use for drawing */ void drawFooter(video::IVideoDriver *driver); /** * load a texture for a specified layer * @param layer draw layer to specify texture * @param texturepath full path of texture to load */ bool setTexture(texture_layer layer, const std::string &texturepath, bool tile_image, unsigned int minsize); /** * download a file using curl * @param url url to download * @param target file to store to */ static bool downloadFile(const std::string &url, const std::string &target); /** array containing pointers to current specified texture layers */ image_definition m_textures[TEX_LAYER_MAX]; /** * specify text to appear as top left string * @param text to set */ void setTopleftText(const std::string &text); /** pointer to gui element shown at topleft corner */ irr::gui::IGUIStaticText *m_irr_toplefttext = nullptr; /** and text that is in it */ EnrichedString m_toplefttext; /** initialize cloud subsystem */ void cloudInit(); /** do preprocessing for cloud subsystem */ void cloudPreProcess(); /** do postprocessing for cloud subsystem */ void cloudPostProcess(); /** internam data required for drawing clouds */ struct clouddata { /** delta time since last cloud processing */ f32 dtime; /** absolute time of last cloud processing */ u32 lasttime; /** pointer to cloud class */ Clouds *clouds = nullptr; /** camera required for drawing clouds */ scene::ICameraSceneNode *camera = nullptr; }; /** is drawing of clouds enabled atm */ bool m_clouds_enabled = true; /** data used to draw clouds */ clouddata m_cloud; /** start playing a sound and return handle */ s32 playSound(const SimpleSoundSpec &spec, bool looped); /** stop playing a sound started with playSound() */ void stopSound(s32 handle); };