]> git.proxmox.com Git - mirror_novnc.git/commitdiff
Show rect/enc counts, add vnc_perf.html test.
authorJoel Martin <github@martintribe.org>
Sat, 25 Sep 2010 20:50:43 +0000 (15:50 -0500)
committerJoel Martin <github@martintribe.org>
Sat, 25 Sep 2010 20:50:43 +0000 (15:50 -0500)
- include/rfb.js: Keep track of the number of rects of each encoding
  type and print them out when we close a connection (if 'info'
  logging level).

- tests/vnc_perf.html: first pass at a noVNC based performance
  benchmark.

- utils/wsproxy.py: Fix the output of the record filename.

include/rfb.js
tests/vnc_perf.html [new file with mode: 0644]
utils/wsproxy.py

index 38812704618772e71610cc9d35f5cd7620aba907..dd073894a60261f7300403e6e52c6012d62d019b 100644 (file)
@@ -18,7 +18,7 @@ var that           = {},         // Public API interface
 
     // Pre-declare private functions used before definitions (jslint)
     init_vars, updateState, init_msg, normal_msg, recv_message,
-    framebufferUpdate,
+    framebufferUpdate, print_stats,
 
     pixelFormat, clientEncodings, fbUpdateRequest,
     keyEvent, pointerEvent, clientCutText,
@@ -61,6 +61,7 @@ var that           = {},         // Public API interface
 
     encHandlers    = {},
     encNames       = {}, 
+    encStats       = {},     // [rectCnt, rectCntTot]
 
     ws             = null,   // Web Socket object
     canvas         = null,   // Canvas object
@@ -216,6 +217,7 @@ function constructor() {
     for (i=0; i < encodings.length; i+=1) {
         encHandlers[encodings[i][1]] = encHandlers[encodings[i][0]];
         encNames[encodings[i][1]] = encodings[i][0];
+        encStats[encodings[i][1]] = [0, 0];
     }
     // Initialize canvas
     try {
@@ -309,6 +311,32 @@ init_vars = function() {
     FBU.imgQ         = []; // TIGHT_PNG image queue
     mouse_buttonMask = 0;
     mouse_arr        = [];
+
+    // Clear the per connection encoding stats
+    for (i=0; i < encodings.length; i+=1) {
+        encStats[encodings[i][1]][0] = 0;
+    }
+};
+
+// Print statistics
+print_stats = function() {
+    var i, encName, s;
+    Util.Info("Encoding stats for this connection:");
+    for (i=0; i < encodings.length; i+=1) {
+        s = encStats[encodings[i][1]];
+        if ((s[0] + s[1]) > 0) {
+            Util.Info("    " + encodings[i][0] + ": " +
+                      s[0] + " rects");
+        }
+    }
+    Util.Info("Encoding stats since page load:");
+    for (i=0; i < encodings.length; i+=1) {
+        s = encStats[encodings[i][1]];
+        if ((s[0] + s[1]) > 0) {
+            Util.Info("    " + encodings[i][0] + ": "
+                      + s[1] + " rects");
+        }
+    }
 };
 
 //
@@ -440,6 +468,8 @@ updateState = function(state, statusMsg) {
                 }, conf.disconnectTimeout * 1000);
         }
 
+        print_stats();
+
         // WebSocket.onclose transitions to 'disconnected'
         break;
 
@@ -944,7 +974,7 @@ normal_msg = function() {
 };
 
 framebufferUpdate = function() {
-    var now, hdr, fbu_rt_diff, last_bytes, last_rects, ret = true;
+    var now, hdr, fbu_rt_diff, ret = true, ctx;
 
     if (FBU.rects === 0) {
         //Util.Debug("New FBU: rQ.slice(0,20): " + rQ.slice(0,20));
@@ -1011,15 +1041,17 @@ framebufferUpdate = function() {
         }
 
         timing.last_fbu = (new Date()).getTime();
-        last_bytes = rQlen();
-        last_rects = FBU.rects;
 
-        // false ret means need more data
         ret = encHandlers[FBU.encoding]();
 
         now = (new Date()).getTime();
         timing.cur_fbu += (now - timing.last_fbu);
 
+        if (ret) {
+            encStats[FBU.encoding][0] += 1;
+            encStats[FBU.encoding][1] += 1;
+        }
+
         if (FBU.rects === 0) {
             if (((FBU.width === fb_width) &&
                         (FBU.height === fb_height)) ||
@@ -1058,7 +1090,7 @@ framebufferUpdate = function() {
 //
 
 encHandlers.RAW = function display_raw() {
-    //Util.Debug(">> display_raw");
+    //Util.Debug(">> display_raw (" + rQlen() + " bytes)");
 
     var cur_y, cur_height; 
 
@@ -1084,6 +1116,7 @@ encHandlers.RAW = function display_raw() {
         FBU.rects -= 1;
         FBU.bytes = 0;
     }
+    //Util.Debug("<< display_raw (" + rQlen() + " bytes)");
     return true;
 };
 
diff --git a/tests/vnc_perf.html b/tests/vnc_perf.html
new file mode 100644 (file)
index 0000000..8e9c925
--- /dev/null
@@ -0,0 +1,197 @@
+<html>
+    <head>
+        <title>VNC Performance Benchmark</title>
+        <link rel="stylesheet" href="include/plain.css">
+    </head>
+    <body>
+
+        Passes: <input id='passes' style='width:50' value=3>&nbsp;
+
+        <input id='startButton' type='button' value='Start' style='width:100px'
+            onclick="start();" disabled>&nbsp;
+
+        <br><br>
+
+        Results:<br>
+        <textarea id="messages" style="font-size: 9;" cols=80 rows=15></textarea>
+
+        <br><br>
+
+        <div id="VNC_screen">
+            <div id="VNC_status_bar" class="VNC_status_bar" style="margin-top: 0px;">
+                <table border=0 width=100%><tr>
+                    <td><div id="VNC_status">Loading</div></td>
+                </tr></table>
+            </div>
+            <canvas id="VNC_canvas" width="640px" height="20px">
+                Canvas not supported.
+            </canvas>
+        </div>
+
+    </body>
+
+    <!--
+    <script type='text/javascript' 
+        src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
+    -->
+
+    <script src="include/vnc.js"></script>
+    <script src="include/playback.js"></script>
+    <script src="data_multi.js"></script>
+
+    <script>
+        var start_time, VNC_frame_data, pass, passes, encIdx,
+            encOrder = ['raw', 'rre', 'hextile', 'tightpng', 'copyrect'],
+            encTot = {}, encMin = {}, encMax = {},
+            passCur, passTot, passMin, passMax;
+
+        function msg(str) {
+            console.log(str);
+            var cell = $('messages');
+            cell.innerHTML += str + "\n";
+            cell.scrollTop = cell.scrollHeight;
+        }
+        function dbgmsg(str) {
+            if (Util.get_logging() === 'debug') {
+                msg(str);
+            }
+        }
+
+        updateState = function (rfb, state, oldstate, mesg) {
+            switch (state) {
+                case 'failed':
+                case 'fatal':
+                    msg("noVNC sent '" + state +
+                        "' state during pass " + pass +
+                        ", iteration " + iteration +
+                        " frame " + frame_idx);
+                    test_state = 'failed';
+                    break;
+                case 'loaded':
+                    $('startButton').disabled = false;
+                    break;
+            }
+            if (typeof mesg !== 'undefined') {
+                $('VNC_status').innerHTML = mesg;
+            }
+        }
+
+        function start() {
+            $('startButton').value = "Running";
+            $('startButton').disabled = true;
+
+            mode = 'perftest'; // full-speed
+            passes = $('passes').value;
+            pass = 1;
+            encIdx = 0;
+
+            // Render each encoding once for each pass
+            iterations = 1;
+
+            // Initialize stats counters
+            for (i = 0; i < encOrder.length; i++) {
+                enc = encOrder[i];
+                encTot[i] = 0;
+                encMin[i] = 2<<23; // Something sufficiently large
+                encMax[i] = 0;
+            }
+            passCur = 0;
+            passTot = 0;
+            passMin = 2<<23;
+            passMax = 0;
+
+            // Fire away
+            next_encoding();
+        }
+
+        function next_encoding() {
+            var encName;
+
+            if (encIdx >= encOrder.length) {
+                // Accumulate pass stats
+                if (passCur < passMin) {
+                    passMin = passCur;
+                }
+                if (passCur > passMax) {
+                    passMax = passCur;
+                }
+                msg("Pass " + pass + " took " + passCur + " ms");
+
+                passCur = 0;
+                encIdx = 0;
+                pass += 1;
+                if (pass > passes) {
+                    // We are finished
+                    rfb.get_canvas().stop();   // Shut-off event interception
+                    $('startButton').disabled = false;
+                    $('startButton').value = "Start";
+                    finish_passes();
+                    return; // We are finished, terminate
+                }
+            }
+
+            encName = encOrder[encIdx];
+            dbgmsg("Rendering pass " + pass + " encoding '" + encName + "'");
+
+            VNC_frame_data = VNC_frame_data_multi[encName];
+            iteration = 0;
+            start_time = (new Date()).getTime();
+
+            next_iteration();
+        }
+
+        // Finished rendering current encoding
+        function finish() {
+            var total_time, end_time = (new Date()).getTime();
+            total_time = end_time - start_time;
+
+            dbgmsg("Encoding " + encOrder[encIdx] + " took " + total_time + "ms");
+
+            passCur += total_time;
+            passTot += total_time;
+
+            // Accumulate stats
+            encTot[encIdx] += total_time;
+            if (total_time < encMin[encIdx]) {
+                encMin[encIdx] = total_time;
+            }
+            if (total_time > encMax[encIdx]) {
+                encMax[encIdx] = total_time;
+            }
+
+            encIdx += 1;
+            next_encoding();
+        }
+
+        function finish_passes() {
+            var i, enc, avg, passAvg;
+            msg("STATS (for " + passes + " passes)");
+            // Encoding stats
+            for (i = 0; i < encOrder.length; i++) {
+                enc = encOrder[i];
+                avg = (encTot[i] / passes).toFixed(1);
+                msg("  " + enc + ": " + encTot[i] + " ms, " +
+                    encMin[i] + "/" + avg + "/" + encMax[i] + 
+                    " (min/avg/max)");
+
+            }
+            // Print pass stats
+            passAvg = (passTot / passes).toFixed(1);
+            msg("\n  All passes: " + passTot + " ms, " +
+                passMin + "/" + passAvg + "/" + passMax +
+                " (min/avg/max)");
+        }
+
+        window.onload = function() {
+            var i, enc;
+            dbgmsg("Frame lengths:");
+            for (i = 0; i < encOrder.length; i++) {
+                enc = encOrder[i];
+                dbgmsg("  " + enc + ": " + VNC_frame_data_multi[enc].length);
+            }
+            rfb = RFB({'target': 'VNC_canvas',
+                    'updateState': updateState});
+            rfb.testMode(send_array);
+        }
+    </script>
+</html>
index 2615c3c4974ff9353f8bf242687f47eb737da542..71fe5774295ed46ef98263204a3854c5decea60f 100755 (executable)
@@ -101,12 +101,13 @@ def do_proxy(client, target):
                 cpartial = cpartial + buf
 
 def proxy_handler(client):
-    global target_host, target_port, options, rec
+    global target_host, target_port, options, rec, fname
 
     if settings['record']:
-        handler_msg("opening record file: %s" % settings['record'])
-        rec = open("%s.%s" % (settings['record'],
-                              settings['handler_id']), 'w+')
+        fname = "%s.%s" % (settings['record'],
+                            settings['handler_id'])
+        handler_msg("opening record file: %s" % fname)
+        rec = open(fname, 'w+')
         rec.write("var VNC_frame_data = [\n")
 
     handler_msg("connecting to: %s:%s" % (target_host, target_port))