]> git.cworth.org Git - apitrace/commitdiff
Merge branch 'libbacktrace'
authorJosé Fonseca <jfonseca@vmware.com>
Tue, 28 May 2013 10:48:00 +0000 (11:48 +0100)
committerJosé Fonseca <jfonseca@vmware.com>
Tue, 28 May 2013 10:48:00 +0000 (11:48 +0100)
Android.mk
common/os_posix.cpp
common/os_string.hpp
common/os_win32.cpp
dispatch/dlopen.hpp
retrace/retrace.py
retrace/retrace_main.cpp
retrace/retrace_swizzle.cpp
scripts/jsonextractimages.py [new file with mode: 0755]
scripts/retracediff.py
scripts/tracecheck.py

index ad742f3d3f32fbb59b31e086472ae7a80317051c..7e4c7a7880420613b046628617f6bad9a1341962 100644 (file)
@@ -7,6 +7,11 @@
 # This may work in other than FirefoxOS environments, but has not been tested.
 #
 
+ifeq ($(shell which cmake),)
+$(shell echo "CMake not found, will not compile apitrace" >&2)
+else # cmake
+$(shell echo "CMake found, will compile apitrace" >&2)
+
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
@@ -46,6 +51,7 @@ apitrace_private_target:
                -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/android.toolchain.cmake \
                -DANDROID_NDK=../../prebuilt/ndk/android-ndk-r7 \
                -DANDROID_NDK_LAYOUT=LINARO \
+               -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.4.x \
                -DANDROID_API_LEVEL=9 \
                -DANDROID_NO_UNDEFINED=OFF \
                -DLIBRARY_OUTPUT_PATH_ROOT=../../$(MY_APITRACE_BUILD_ROOT_TARGET) \
@@ -77,3 +83,5 @@ $(linked_module): apitrace_private_target
        $(hide) # apitrace: copy apitrace executable to where the build system expects it
        $(hide) mkdir -p $(dir $@)
        $(hide) cp $(MY_APITRACE_BUILD_ROOT_TARGET)/apitrace$(TARGET_EXECUTABLE_SUFFIX) $@
+
+endif # cmake
index 5ec8b363390792748e733a6d8d5e7a9b3afadb24..05ad8e987cdcf4365a8ab0cf7f209f9be07955f5 100644 (file)
@@ -111,6 +111,12 @@ getCurrentDir(void)
     return path;
 }
 
+bool
+createDirectory(const String &path)
+{
+    return mkdir(path, 0777) == 0;
+}
+
 bool
 String::exists(void) const
 {
index 78d02f2cacc5a4bbefcf430249a74361b068377a..3a8eab688552b1bb39f187bc57fc2981f4e5bd1c 100644 (file)
@@ -130,24 +130,23 @@ protected:
         return false;
     }
 
-    Buffer::iterator rfindSep(void) {
-        Buffer::iterator it = buffer.end();
+public:
 
-        // Skip trailing '\0'
-        assert(it != buffer.begin());
-        --it;
-        assert(*it == '\0');
+    Buffer::iterator rfindSep(bool skipTrailing = true) {
+        Buffer::iterator it = end();
 
         // Skip trailing separators
-        while (it != buffer.begin()) {
-            --it;
-            if (isSep(*it)) {
-                // Halt if find the root
-                if (it == buffer.begin()) {
-                    return it;
+        if (skipTrailing) {
+            while (it != buffer.begin()) {
+                --it;
+                if (isSep(*it)) {
+                    // Halt if find the root
+                    if (it == buffer.begin()) {
+                        return it;
+                    }
+                } else {
+                    break;
                 }
-            } else {
-                break;
             }
         }
 
@@ -159,12 +158,9 @@ protected:
             }
         }
 
-        return buffer.end();
+        return end();
     }
 
-
-public:
-
     /*
      * Constructors
      */
@@ -309,6 +305,11 @@ public:
         insert(end(), other);
     }
 
+    template <class InputIterator>
+    void erase(InputIterator first, InputIterator last) {
+        buffer.erase(first, last);
+    }
+
     char *buf(size_t size) {
         buffer.resize(size);
         return &buffer[0];
@@ -343,7 +344,7 @@ public:
      */
     void trimDirectory(void) {
         iterator sep = rfindSep();
-        if (sep != buffer.end()) {
+        if (sep != end()) {
             buffer.erase(buffer.begin(), sep + 1);
         }
     }
@@ -358,7 +359,7 @@ public:
         iterator sep = rfindSep();
 
         // No separator found, so return '.'
-        if (sep == buffer.end()) {
+        if (sep == end()) {
             buffer.resize(2);
             buffer[0] = '.';
             buffer[1] = 0;
@@ -393,6 +394,8 @@ public:
 String getProcessName();
 String getCurrentDir();
 
+bool createDirectory(const String &path);
+
 bool copyFile(const String &srcFileName, const String &dstFileName, bool override = true);
 
 bool removeFile(const String &fileName);
index f297a5551357f5b7631519374bc4ad36149090a6..c5be8a88efb190f904d2af4fd098e77cbfab1093 100644 (file)
@@ -69,6 +69,12 @@ getCurrentDir(void)
     return path;
 }
 
+bool
+createDirectory(const String &path)
+{
+    return CreateDirectoryA(path, NULL);
+}
+
 bool
 String::exists(void) const
 {
index cb59a444029b931b07273529f3dcbc24255b0ea2..c1a71ba8b7fd03463dd7e68855117e72c965854b 100644 (file)
@@ -38,7 +38,8 @@
 /*
  * Invoke the true dlopen() function.
  */
-static void *_dlopen(const char *filename, int flag)
+static inline void *
+_dlopen(const char *filename, int flag)
 {
     typedef void * (*PFN_DLOPEN)(const char *, int);
     static PFN_DLOPEN dlopen_ptr = NULL;
index cc3081da7d744cf237fcca2ee36d96c623008bb4..aa2036455ebff631451f0c912051f8bcc0973e7d 100644 (file)
@@ -493,7 +493,8 @@ class Retracer:
     def checkResult(self, resultType):
         if str(resultType) == 'HRESULT':
             print r'    if (FAILED(_result)) {'
-            print r'        retrace::warning(call) << "failed (0x" << std::hex << _result << std::dec << ")\n";'
+            print '         static char szMessageBuffer[128];'
+            print r'        retrace::warning(call) << "call returned 0x" << std::hex << _result << std::dec << ": " << (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, _result, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), szMessageBuffer, sizeof szMessageBuffer, NULL) ? szMessageBuffer : "???") << "\n";'
             print r'    }'
 
     def filterFunction(self, function):
index 5e31c020490ab86beccb3635914fa82d9e83d479..ddcc27fb82e1133bd2febf717b4ebb0b7b99d8c9 100644 (file)
@@ -714,6 +714,23 @@ int main(int argc, char **argv)
             if (snapshotPrefix[0] == '-' && snapshotPrefix[1] == 0) {
                 os::setBinaryMode(stdout);
                 retrace::verbosity = -2;
+            } else {
+                /*
+                 * Create the snapshot directory if it does not exist.
+                 *
+                 * We can't just use trimFilename() because when applied to
+                 * "/foo/boo/" it would merely return "/foo".
+                 *
+                 * XXX: create nested directories.
+                 */
+                os::String prefix(snapshotPrefix);
+                os::String::iterator sep = prefix.rfindSep(false);
+                if (sep != prefix.end()) {
+                    prefix.erase(sep, prefix.end());
+                    if (!os::createDirectory(prefix)) {
+                        std::cerr << "error: failed to create " << prefix.str() << "\n";
+                    }
+                }
             }
             break;
        case SNAPSHOT_FORMAT_OPT:
index 2045f6bb7c83eafe5e71cca35141ce19080e7a1a..f1a10d5e9ea03a33249357cb3c5c830fdbd3d775 100644 (file)
@@ -280,6 +280,9 @@ void
 delObj(trace::Value &value) {
     unsigned long long address = value.toUIntPtr();
     _obj_map.erase(address);
+    if (retrace::verbosity >= 2) {
+        std::cout << std::hex << "obj 0x" << address << " del\n";
+    }
 }
 
 void *
diff --git a/scripts/jsonextractimages.py b/scripts/jsonextractimages.py
new file mode 100755 (executable)
index 0000000..c47ffc8
--- /dev/null
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+##########################################################################
+#
+# Copyright 2012 Jose Fonseca
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+'''Simple script to extract PNG files from the JSON state dumps.'''
+
+
+import json
+import optparse
+import base64
+import sys
+
+
+def dumpSurfaces(state, memberName):
+    for name, imageObj in state[memberName].iteritems():
+        data = imageObj['__data__']
+        data = base64.b64decode(data)
+
+        imageName = '%s.png' % name
+        open(imageName, 'wb').write(data)
+        sys.stderr.write('Wrote %s\n' % imageName)
+
+
+def main():
+    optparser = optparse.OptionParser(
+        usage="\n\t%prog [options] <json>")
+
+    (options, args) = optparser.parse_args(sys.argv[1:])
+
+    for arg in args:
+        state = json.load(open(arg, 'rt'), strict=False)
+
+        dumpSurfaces(state, 'textures')
+        dumpSurfaces(state, 'framebuffer')
+
+
+
+if __name__ == '__main__':
+    main()
index 171622d03a1ea942b2073e53ee92a2f3feaf264e..e59d00a5b65fa74af41d25dcdf4bf0c025e05136 100755 (executable)
@@ -48,31 +48,60 @@ else:
     NULL = open('/dev/null', 'wt')
 
 
-class Setup:
+class RetraceRun:
 
-    def __init__(self, args, env=None):
+    def __init__(self, process):
+        self.process = process
+
+    def nextSnapshot(self):
+        image, comment = read_pnm(self.process.stdout)
+        if image is None:
+            return None, None
+
+        callNo = int(comment.strip())
+
+        return image, callNo
+
+    def terminate(self):
+        try:
+            self.process.terminate()
+        except OSError:
+            # Avoid http://bugs.python.org/issue14252
+            pass
+
+
+class Retracer:
+
+    def __init__(self, retraceExe, args, env=None):
+        self.retraceExe = retraceExe
         self.args = args
         self.env = env
 
-    def _retrace(self, args):
+    def _retrace(self, args, stdout=subprocess.PIPE):
         cmd = [
-            options.retrace,
+            self.retraceExe,
         ] + args + self.args
         if self.env:
             for name, value in self.env.iteritems():
                 sys.stderr.write('%s=%s ' % (name, value))
         sys.stderr.write(' '.join(cmd) + '\n')
         try:
-            return subprocess.Popen(cmd, env=self.env, stdout=subprocess.PIPE, stderr=NULL)
+            return subprocess.Popen(cmd, env=self.env, stdout=stdout, stderr=NULL)
         except OSError, ex:
             sys.stderr.write('error: failed to execute %s: %s\n' % (cmd[0], ex.strerror))
             sys.exit(1)
 
-    def retrace(self):
-        return self._retrace([
+    def retrace(self, args):
+        p = self._retrace([])
+        p.wait()
+        return p.returncode
+
+    def snapshot(self, call_nos):
+        process = self._retrace([
             '-s', '-',
-            '-S', options.snapshot_frequency,
+            '-S', call_nos,
         ])
+        return RetraceRun(process)
 
     def dump_state(self, call_no):
         '''Get the state dump at the specified call no.'''
@@ -206,8 +235,8 @@ def main():
     if options.src_driver:
         options.src_args.insert(0, '--driver=' + options.src_driver)
 
-    ref_setup = Setup(options.ref_args + args, ref_env)
-    src_setup = Setup(options.src_args + args, src_env)
+    refRetracer = Retracer(options.retrace, options.ref_args + args, ref_env)
+    srcRetracer = Retracer(options.retrace, options.src_args + args, src_env)
 
     if options.output:
         output = open(options.output, 'wt')
@@ -220,27 +249,26 @@ def main():
 
     last_bad = -1
     last_good = 0
-    ref_proc = ref_setup.retrace()
+    refRun = refRetracer.snapshot(options.snapshot_frequency)
     try:
-        src_proc = src_setup.retrace()
+        srcRun = srcRetracer.snapshot(options.snapshot_frequency)
         try:
             while True:
                 # Get the reference image
-                ref_image, ref_comment = read_pnm(ref_proc.stdout)
-                if ref_image is None:
+                refImage, refCallNo = refRun.nextSnapshot()
+                if refImage is None:
                     break
 
                 # Get the source image
-                src_image, src_comment = read_pnm(src_proc.stdout)
-                if src_image is None:
+                srcImage, srcCallNo = srcRun.nextSnapshot()
+                if srcImage is None:
                     break
 
-                assert ref_comment == src_comment
-
-                call_no = int(ref_comment.strip())
+                assert refCallNo == srcCallNo
+                callNo = refCallNo
 
                 # Compare the two images
-                comparer = Comparer(ref_image, src_image)
+                comparer = Comparer(refImage, srcImage)
                 precision = comparer.precision()
 
                 mismatch = precision < options.threshold
@@ -248,38 +276,30 @@ def main():
                 if mismatch:
                     highligher.color(highligher.red)
                     highligher.bold()
-                highligher.write('%u\t%f\n' % (call_no, precision))
+                highligher.write('%u\t%f\n' % (callNo, precision))
                 if mismatch:
                     highligher.normal()
 
                 if mismatch:
                     if options.diff_prefix:
-                        prefix = os.path.join(options.diff_prefix, '%010u' % call_no)
+                        prefix = os.path.join(options.diff_prefix, '%010u' % callNo)
                         prefix_dir = os.path.dirname(prefix)
                         if not os.path.isdir(prefix_dir):
                             os.makedirs(prefix_dir)
-                        ref_image.save(prefix + '.ref.png')
-                        src_image.save(prefix + '.src.png')
+                        refImage.save(prefix + '.ref.png')
+                        srcImage.save(prefix + '.src.png')
                         comparer.write_diff(prefix + '.diff.png')
                     if last_bad < last_good:
-                        src_setup.diff_state(last_good, call_no, output)
-                    last_bad = call_no
+                        srcRetracer.diff_state(last_good, callNo, output)
+                    last_bad = callNo
                 else:
-                    last_good = call_no
+                    last_good = callNo
 
                 highligher.flush()
         finally:
-            try:
-                src_proc.terminate()
-            except OSError:
-                # Avoid http://bugs.python.org/issue14252
-                pass
+            srcRun.terminate()
     finally:
-        try:
-            ref_proc.terminate()
-        except OSError:
-            # Avoid http://bugs.python.org/issue14252
-            pass
+        refRun.terminate()
 
 
 if __name__ == '__main__':
index d204fa63dbfcbc7a7a6672b888cfea3caac35078..3a2ec452192f58dc99a31d524d20c1156ca86f06 100755 (executable)
@@ -39,6 +39,9 @@ import subprocess
 import sys
 import traceback
 
+import snapdiff
+import retracediff
+
 
 def good():
     '''Tell git-bisect that this commit is good.'''
@@ -142,9 +145,9 @@ def main():
     # implementation is usable, and is the right one (i.e., we didn't fallback
     # to a different OpenGL implementation due to missing symbols).
     if platform.system() != 'Windows' and which('glxinfo'):
-        p = subprocess.Popen(['glxinfo'], stdout=subprocess.PIPE)
-        stdout, stderr = p.communicate()
-        if p.returncode:
+        glxinfo = subprocess.Popen(['glxinfo'], stdout=subprocess.PIPE)
+        stdout, stderr = glxinfo.communicate()
+        if glxinfo.returncode:
             skip()
 
         # Search for the GL_RENDERER string
@@ -164,34 +167,45 @@ def main():
             skip()
 
     # Run glretrace
-    command = [options.retrace]
-    if options.compare_prefix:
-        command += ['-c', options.compare_prefix]
-    else:
-        command += ['-b']
-    command += args
-    sys.stdout.write(' '.join(command) + '\n')
-    sys.stdout.flush()
-    p = subprocess.Popen(command, stdout=subprocess.PIPE)
-    stdout, stderr = p.communicate()
-    if p.returncode:
-        if not options.compare_prefix:
-            bad()
-        else:
-            skip()
+    
+    retracer = retracediff.Retracer(options.retrace, args)
 
     if options.compare_prefix:
-        failed = False
-        precision_re = re.compile('^Snapshot (\S+) average precision of (\S+) bits$')
-        for line in stdout.split('\n'):
-            mo = precision_re.match(line)
-            if mo:
-                print line
-                call_no = int(mo.group(1))
-                precision = float(mo.group(2))
-                if precision < options.precision_threshold:
-                    failed = True
-        if failed:
+        refImages = {}
+        callNos = []
+            
+        images = snapdiff.find_images(options.compare_prefix)
+        images.sort()
+        for image in images:
+            imageName, ext = os.path.splitext(image)
+            try:
+                callNo = int(imageName)
+            except ValueError:
+                continue
+            refImages[callNo] = options.compare_prefix + image
+            callNos.append(callNo)
+
+        run = retracer.snapshot(','.join(map(str, callNos)))
+        while True:
+            srcImage, callNo = run.nextSnapshot()
+            if srcImage is None:
+                break
+
+            refImage = refImages[callNo]
+
+            # Compare the two images
+            comparer = snapdiff.Comparer(refImage, srcImage)
+            precision = comparer.precision()
+
+            mismatch = precision < options.precision_threshold
+            if mismatch:
+                bad()
+        run.process.wait()
+        if run.process.returncode:
+            skip()
+    else:
+        returncode = retracer.retrace('-b')
+        if returncode:
             bad()
 
     # TODO: allow more criterias here, such as, performance threshold