]> git.tdb.fi Git - gldbg.git/commitdiff
Add a performance profiler
authorMikko Rasa <tdb@tdb.fi>
Thu, 28 Jan 2010 16:07:52 +0000 (16:07 +0000)
committerMikko Rasa <tdb@tdb.fi>
Thu, 28 Jan 2010 16:07:52 +0000 (16:07 +0000)
Support specifying an alternative OpenGL library
Only return non-null from glXGetProcAddress if the function is found from libGL

Makefile
source/commandinterpreter.cpp
source/commandinterpreter.h
source/gldbg.cpp
source/gldbg.h
source/glwrap.c
source/profiler.cpp [new file with mode: 0644]
source/profiler.h [new file with mode: 0644]

index 60da9b297e1059903c5354f62c558235e9c75fdd..d06ea67e0b66fbef4a2b72472df581c0ee6e1d20 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 # $Id$
 
-CFLAGS = -Igensrc -ggdb -Wall -Wextra -Werror
-CXXFLAGS = -Igensrc -ggdb -Wall -Wextra -Werror
+CFLAGS = -Igensrc -ggdb -Wall -Wextra
+CXXFLAGS = -Igensrc -ggdb -Wall -Wextra
 
 PACKAGES_gldbg = mspcore mspstrings mspio mspfs
 CXXFLAGS_gldbg = $(shell pkg-config --cflags $(PACKAGES_gldbg))
@@ -15,7 +15,7 @@ glwrap.so: source/glwrap.o source/arraysize.o
 gldump: source/gldecoder.o source/gldump.o source/glprint.o source/enums.o source/arraysize.o source/tmpalloc.o
        $(CC) -o $@ $^ $(LIBS) $(LDFLAGS)
 
-gldbg: source/gldbg.o source/gldecoder.o source/glprint.o source/commandinterpreter.o source/tracer.o source/process.o source/enums.o source/arraysize.o source/tmpalloc.o source/glstate.o source/texturestate.o source/bufferstate.o
+gldbg: source/gldbg.o source/gldecoder.o source/glprint.o source/commandinterpreter.o source/tracer.o source/process.o source/enums.o source/arraysize.o source/tmpalloc.o source/glstate.o source/texturestate.o source/bufferstate.o source/profiler.o
        $(CXX) -o $@ $^ $(LIBS_gldbg) $(LIBS) $(LDFLAGS)
 
 source/glwrap.o: source/functions.h gensrc/functions.enum gensrc/glwrap.funcs
@@ -23,7 +23,7 @@ source/gldecoder.o: source/functions.h gensrc/gldecoder.struct gensrc/gldecoder.
 source/gldump.o: source/gldecoder.h gensrc/gldecoder.struct source/glprint.h
 source/glprint.o: source/arraysize.h gensrc/glprint.funcs gensrc/gldecoder.struct
 source/enums.o: gensrc/enums.table
-source/gldbg.o: source/gldbg.h source/gldecoder.h source/tracer.h source/commandinterpreter.h source/glstate.h
+source/gldbg.o: source/gldbg.h source/gldecoder.h source/tracer.h source/commandinterpreter.h source/glstate.h source/profiler.h
 source/tracer.o: source/gldecoder.h source/glprint.h
 source/commandinterpreter.o: source/gldbg.h source/glstate.h
 source/process.o: source/process.h
index abc9dda60b07bc83d5125eac1612f8096d5e25eb..c684979bae2061b49f9fddd06a8cead8c381e9d6 100644 (file)
@@ -57,6 +57,11 @@ CommandInterpreter::CommandInterpreter(GlDbg &d):
                "trace end\n"
                "  Terminate trace, closing the file.\n");
 
+       commands["profile"] = Command(&CommandInterpreter::cmd_profile,
+               "Profiles GL usage and performance",
+               "profile {on|off}\n"
+               "  Enables or disables profiling\n");
+
        commands["state"] = Command(&CommandInterpreter::cmd_state,
                "Inspects general GL state",
                "state vertex\n"
@@ -202,6 +207,17 @@ void CommandInterpreter::cmd_trace(const string &args)
        }
 }
 
+void CommandInterpreter::cmd_profile(const string &args)
+{
+       Profiler &profiler = gldbg.get_profiler();
+       if(args.empty() || args=="on")
+               profiler.enable();
+       else if(args=="off")
+               profiler.disable();
+       else
+               throw InvalidParameterValue("Invalid argument");
+}
+
 void CommandInterpreter::cmd_state(const string &args)
 {
        const GlState &glstate = gldbg.get_glstate();
index 14d8eb96d3a32521fd105e23321792c000025dd3..852ba65781241a3e12847ec4dc70b37ec067da2d 100644 (file)
@@ -46,6 +46,7 @@ private:
        void cmd_kill(const std::string &);
        void cmd_exit(const std::string &);
        void cmd_trace(const std::string &);
+       void cmd_profile(const std::string &);
        void cmd_state(const std::string &);
        void cmd_texture(const std::string &);
        void cmd_buffer(const std::string &);
index 34e616f4ac37caa5d30da1708892206bc3dea597..d18ff51bba753b9c2ccbb97cb510d48169fa957a 100644 (file)
@@ -135,6 +135,7 @@ void GlDbg::read_stream()
                                        break;
                                tracer.decode(data, len);
                                glstate.decode(data, len);
+                               profiler.decode(data, len);
                                buf_offset += size;
                        }
                        if(buf_offset>8192)
index 5654715c41845ffca052bbef67f936b86846ec68..e42e4aa1d1425cb5c105bca4528d6835ad81ad77 100644 (file)
@@ -15,6 +15,7 @@ Distributed under the GPL
 #include "commandinterpreter.h"
 #include "glstate.h"
 #include "process.h"
+#include "profiler.h"
 #include "tracer.h"
 
 class GlDbg: public Msp::Application
@@ -28,6 +29,7 @@ private:
        bool flushing;
        Tracer tracer;
        GlState glstate;
+       Profiler profiler;
        bool got_sigchld;
 
        static RegApp<GlDbg> reg;
@@ -37,6 +39,7 @@ public:
        int main();
        Tracer &get_tracer() { return tracer; }
        GlState &get_glstate() { return glstate; }
+       Profiler &get_profiler() { return profiler; }
        Process &get_process() { return process; }
        void launch();
        void quit(bool);
index d51eb3192106b9ce94fa77b200a2c6797565f0de..bf05214b8a09d7ee844d5567626b395b2066f1db 100644 (file)
@@ -21,10 +21,13 @@ static inline void *glsym(const char *sym)
        static void *libgl = NULL;
        if(!libgl)
        {
-               libgl = dlopen("libGL.so", RTLD_NOW);
+               const char *libgl_name = getenv("GLWRAP_LIBGL");
+               if(!libgl_name)
+                       libgl_name = "libGL.so";
+               libgl = dlopen(libgl_name, RTLD_NOW);
                if(!libgl)
                {
-                       fprintf(stderr, "Could not open libGL: %s\n", dlerror());
+                       fprintf(stderr, "Could not open %s: %s\n", libgl_name, dlerror());
                        abort();
                }
        }
@@ -188,12 +191,20 @@ GLenum APIENTRY glGetError()
 
 void (*glXGetProcAddress(const GLubyte *procname))(void)
 {
-       void *handle = dlopen(NULL, RTLD_LAZY);
-       void (*ret)() = dlsym(handle, (const char *)procname);
+       void *handle = 0;
+       void (*ret)() = 0;
+
+       if(glsym((const char *)procname))
+       {
+               handle = dlopen(NULL, RTLD_LAZY);
+               ret = dlsym(handle, (const char *)procname);
+       }
+
        begin_packet(FUNC_GLXGETPROCADDRESS);
        write_pointer(ret);
-       write_string(procname);
+       write_string((const char *)procname);
        send_packet();
+
        return ret;
 }
 
diff --git a/source/profiler.cpp b/source/profiler.cpp
new file mode 100644 (file)
index 0000000..ec9138d
--- /dev/null
@@ -0,0 +1,96 @@
+#include <msp/io/print.h>
+#include <msp/time/units.h>
+#include <msp/time/utils.h>
+#include "profiler.h"
+
+using namespace Msp;
+
+Profiler::Profiler():
+       decoder(gldecoder_new(this, 0)),
+       enabled(false)
+{
+       decoder->glDrawArrays = glDrawArrays;
+       decoder->glDrawElements = glDrawElements;
+       decoder->glDrawRangeElements = glDrawRangeElements;
+       decoder->glXSwapBuffers = glXSwapBuffers;
+}
+
+void Profiler::enable()
+{
+       enabled = true;
+       frames = 0;
+       draw_calls = 0;
+       vertices = 0;
+       triangles = 0;
+       start = Msp::Time::now();
+}
+
+void Profiler::disable()
+{
+       enabled = false;
+}
+
+int Profiler::decode(const char *data, unsigned len)
+{
+       if(enabled)
+               return gldecoder_decode(decoder, data, len);
+       else
+               return 0;
+}
+
+void Profiler::glDrawArrays(void *user_data, GLenum mode, int, int count)
+{
+       glDrawElements(user_data, mode, count, 0, 0);
+}
+
+void Profiler::glDrawElements(void *user_data, GLenum mode, int count, GLenum, const void *)
+{
+       Profiler *self = reinterpret_cast<Profiler *>(user_data);
+
+       ++self->draw_calls;
+       self->vertices += count;
+
+       switch(mode)
+       {
+       case GL_TRIANGLES:
+               self->triangles += count/3;
+               break;
+       case GL_TRIANGLE_STRIP:
+       case GL_TRIANGLE_FAN:
+               if(count>2)
+                       self->triangles += count-2;
+               break;
+       case GL_QUADS:
+               self->triangles += count/4;
+               break;
+       case GL_QUAD_STRIP:
+               if(count>3)
+                       self->triangles += count/2-1;
+               break;
+       }
+}
+
+void Profiler::glDrawRangeElements(void *user_data, GLenum mode, unsigned, unsigned, int count, GLenum type, const void *data)
+{
+       glDrawElements(user_data, mode, count, type, data);
+}
+
+void Profiler::glXSwapBuffers(void *user_data, Display *, GLXDrawable)
+{
+       Profiler *self = reinterpret_cast<Profiler *>(user_data);
+
+       IO::print("%d draw calls, %d vertices, %d triangles\n", self->draw_calls, self->vertices, self->triangles);
+       self->draw_calls = 0;
+       self->vertices = 0;
+       self->triangles = 0;
+
+       ++self->frames;
+       Msp::Time::TimeStamp t = Msp::Time::now();
+       Msp::Time::TimeDelta dt = t-self->start;
+       if(dt>Msp::Time::sec)
+       {
+               Msp::IO::print("%d frames in %s seconds\n", self->frames, dt);
+               self->start = t;
+               self->frames = 0;
+       }
+}
diff --git a/source/profiler.h b/source/profiler.h
new file mode 100644 (file)
index 0000000..fa6bcac
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef PROFILER_H_
+#define PROFILER_H_
+
+#include <msp/time/timestamp.h>
+#include "gldecoder.h"
+
+class Profiler
+{
+private:
+       GlDecoder *decoder;
+       bool enabled;
+       Msp::Time::TimeStamp start;
+       unsigned frames;
+       unsigned draw_calls;
+       unsigned vertices;
+       unsigned triangles;
+
+public:
+       Profiler();
+
+       void enable();
+       void disable();
+       int decode(const char *, unsigned);
+private:
+       static void glDrawArrays(void *, GLenum, int, int);
+       static void glDrawElements(void *, GLenum, int, GLenum, const void *);
+       static void glDrawRangeElements(void *, GLenum, unsigned, unsigned, int, GLenum, const void *);
+       static void glXSwapBuffers(void *, Display *, GLXDrawable);
+};
+
+#endif