[script] Prototypical binary translator

Hook into the scanner to write out binary version of the tokenized
objects -- note we bind executable names (i.e. check to see if is an
operator and substitute the name with an operator -- this breaks
overloading of operators by scripts).

By converting scripts to a binary form, they are more compact and
execute faster:

  firefox-world-map.trace 526850146 bytes
              bound.trace 275187755 bytes

[ # ]  backend                         test   min(s) median(s) stddev. count
[  0]     null                        bound   34.481   34.741   0.68%    3/3
[  1]     null            firefox-world-map   89.635   89.716   0.19%    3/3
[  0]      drm                        bound   79.304   79.350   0.61%    3/3
[  1]      drm            firefox-world-map  135.380  135.475   0.58%    3/3
[  0]    image                        bound   95.819   96.258   2.85%    3/3
[  1]    image            firefox-world-map  156.889  156.935   1.36%    3/3
[  0]     xlib                        bound  539.130  550.220   1.40%    3/3
[  1]     xlib            firefox-world-map  596.244  613.487   1.74%    3/3

This trace has a lot of complex paths and the use of binary floating point
reduces the file size by about 50%, with a commensurate reduction in scan
time and significant reduction in operator lookup overhead. Note that this
test is still IO/CPU bound on my i915 with its pitifully slow flash...
This commit is contained in:
Chris Wilson 2009-07-03 00:40:32 +01:00
parent 07c0c8c5c0
commit 23648e2fdf
8 changed files with 916 additions and 343 deletions

View file

@ -1,7 +1,7 @@
SUBDIRS = examples
lib_LTLIBRARIES = libcairo-script-interpreter.la
EXTRA_PROGRAMS = csi-replay csi-exec
EXTRA_PROGRAMS = csi-replay csi-exec csi-bind
AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src
@ -27,5 +27,8 @@ csi_replay_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.l
csi_exec_SOURCES = csi-exec.c
csi_exec_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
csi_bind_SOURCES = csi-bind.c
csi_bind_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
EXTRA_DIST = \
COPYING

View file

@ -40,6 +40,8 @@
#define CHUNK_SIZE 32768
#define OWN_STREAM 0x1
csi_status_t
csi_file_new (csi_t *ctx,
csi_object_t *obj,
@ -56,6 +58,7 @@ csi_file_new (csi_t *ctx,
file->data = NULL;
file->type = STDIO;
file->flags = OWN_STREAM;
file->src = fopen (path, mode);
if (file->src == NULL) {
_csi_slab_free (ctx, file, sizeof (csi_file_t));
@ -75,6 +78,42 @@ csi_file_new (csi_t *ctx,
return CAIRO_STATUS_SUCCESS;
}
csi_status_t
csi_file_new_for_stream (csi_t *ctx,
csi_object_t *obj,
FILE *stream)
{
csi_file_t *file;
file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
if (file == NULL)
return _csi_error (CAIRO_STATUS_NO_MEMORY);
file->base.type = CSI_OBJECT_TYPE_FILE;
file->base.ref = 1;
file->data = NULL;
file->type = STDIO;
file->flags = 0;
file->src = stream;
if (file->src == NULL) {
_csi_slab_free (ctx, file, sizeof (csi_file_t));
return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND);
}
file->data = _csi_alloc (ctx, CHUNK_SIZE);
if (file->data == NULL) {
_csi_slab_free (ctx, file, sizeof (csi_file_t));
return _csi_error (CAIRO_STATUS_NO_MEMORY);
}
file->bp = file->data;
file->rem = 0;
obj->type = CSI_OBJECT_TYPE_FILE;
obj->datum.file = file;
return CAIRO_STATUS_SUCCESS;
}
csi_status_t
csi_file_new_for_bytes (csi_t *ctx,
csi_object_t *obj,
@ -727,7 +766,7 @@ csi_file_new_decrypt (csi_t *ctx, csi_object_t *src, int salt, int discard)
csi_status_t
_csi_file_execute (csi_t *ctx, csi_file_t *obj)
{
return _csi_scan_file (ctx, &ctx->scanner, obj);
return _csi_scan_file (ctx, obj);
}
int
@ -917,7 +956,8 @@ csi_file_close (csi_t *ctx, csi_file_t *file)
switch (file->type) {
case STDIO:
fclose (file->src);
if (file->flags & OWN_STREAM)
fclose (file->src);
break;
case BYTES:
if (file->src != file->data) {

View file

@ -40,6 +40,7 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#ifndef MAX
#define MAX(a,b) (((a)>=(b))?(a):(b))
@ -261,10 +262,11 @@ _init_dictionaries (csi_t *ctx)
csi_status_t status;
csi_stack_t *stack;
csi_object_t obj;
csi_dictionary_t *dict;
csi_dictionary_t *dict, *opcodes;
const csi_operator_def_t *odef;
const csi_integer_constant_def_t *idef;
const csi_real_constant_def_t *rdef;
unsigned n;
stack = &ctx->dstack;
@ -283,12 +285,37 @@ _init_dictionaries (csi_t *ctx)
dict = obj.datum.dictionary;
status = csi_dictionary_new (ctx, &obj);
if (_csi_unlikely (status))
return status;
opcodes = obj.datum.dictionary;
n = 0;
csi_integer_new (&obj, n);
status = csi_dictionary_put (ctx, opcodes, 0, &obj);
if (_csi_unlikely (status))
return status;
ctx->opcode[n++] = NULL;
/* fill systemdict with operators */
for (odef = _csi_operators (); odef->name != NULL; odef++) {
status = _add_operator (ctx, dict, odef);
if (_csi_unlikely (status))
return status;
if (! csi_dictionary_has (opcodes, (csi_name_t) odef->op)) {
csi_integer_new (&obj, n);
status = csi_dictionary_put (ctx,
opcodes, (csi_name_t) odef->op, &obj);
if (_csi_unlikely (status))
return status;
assert (n < sizeof (ctx->opcode) / sizeof (ctx->opcode[0]));
ctx->opcode[n++] = odef->op;
}
}
csi_dictionary_free (ctx, opcodes);
/* add constants */
for (idef = _csi_integer_constants (); idef->name != NULL; idef++) {
@ -365,6 +392,8 @@ _csi_init (csi_t *ctx)
{
csi_status_t status;
memset (ctx, 0, sizeof (*ctx));
ctx->status = CSI_STATUS_SUCCESS;
ctx->ref_count = 1;
@ -391,7 +420,7 @@ FAIL:
}
static void
_csi_fini (csi_t *ctx)
_csi_finish (csi_t *ctx)
{
_csi_stack_fini (ctx, &ctx->ostack);
_csi_stack_fini (ctx, &ctx->dstack);
@ -494,7 +523,7 @@ cairo_script_interpreter_create (void)
{
csi_t *ctx;
ctx = calloc (1, sizeof (csi_t));
ctx = malloc (sizeof (csi_t));
if (ctx == NULL)
return (csi_t *) &_csi_nil;
@ -580,7 +609,7 @@ cairo_script_interpreter_finish (csi_t *ctx)
status = ctx->status;
if (! ctx->finished) {
_csi_fini (ctx);
_csi_finish (ctx);
ctx->finished = 1;
} else if (status == CAIRO_STATUS_SUCCESS) {
status = ctx->status = CSI_STATUS_INTERPRETER_FINISHED;
@ -589,6 +618,23 @@ cairo_script_interpreter_finish (csi_t *ctx)
return status;
}
static void
_csi_fini (csi_t *ctx)
{
if (! ctx->finished)
_csi_finish (ctx);
if (ctx->free_array != NULL)
csi_array_free (ctx, ctx->free_array);
if (ctx->free_dictionary != NULL)
csi_dictionary_free (ctx, ctx->free_dictionary);
if (ctx->free_string != NULL)
csi_string_free (ctx, ctx->free_string);
_csi_slab_fini (ctx);
_csi_perm_fini (ctx);
}
cairo_status_t
cairo_script_interpreter_destroy (csi_t *ctx)
{
@ -598,20 +644,33 @@ cairo_script_interpreter_destroy (csi_t *ctx)
if (--ctx->ref_count)
return status;
if (! ctx->finished)
_csi_fini (ctx);
if (ctx->free_array != NULL)
csi_array_free (ctx, ctx->free_array);
if (ctx->free_dictionary != NULL)
csi_dictionary_free (ctx, ctx->free_dictionary);
if (ctx->free_string != NULL)
csi_string_free (ctx, ctx->free_string);
_csi_slab_fini (ctx);
_csi_perm_fini (ctx);
_csi_fini (ctx);
free (ctx);
return status;
}
slim_hidden_def (cairo_script_interpreter_destroy);
cairo_status_t
cairo_script_interpreter_translate_stream (FILE *stream,
cairo_write_func_t write_func,
void *closure)
{
csi_t ctx;
csi_object_t src;
csi_status_t status;
_csi_init (&ctx);
status = csi_file_new_for_stream (&ctx, &src, stream);
if (status)
goto BAIL;
status = _csi_translate_file (&ctx, src.datum.file, write_func, closure);
BAIL:
csi_object_free (&ctx, &src);
_csi_fini (&ctx);
return status;
}

View file

@ -37,6 +37,7 @@
#define CAIRO_SCRIPT_INTERPRETER_H
#include <cairo.h>
#include <stdio.h>
CAIRO_BEGIN_DECLS
@ -45,7 +46,8 @@ typedef struct _cairo_script_interpreter cairo_script_interpreter_t;
/* XXX expose csi_dictionary_t and pass to hooks */
typedef void
(*csi_destroy_func_t) (void *closure,
void *ptr);
void *ptr);
typedef cairo_surface_t *
(*csi_surface_create_func_t) (void *closure,
cairo_content_t content,
@ -100,6 +102,11 @@ cairo_script_interpreter_finish (cairo_script_interpreter_t *ctx);
cairo_public cairo_status_t
cairo_script_interpreter_destroy (cairo_script_interpreter_t *ctx);
cairo_public cairo_status_t
cairo_script_interpreter_translate_stream (FILE *stream,
cairo_write_func_t write_func,
void *closure);
CAIRO_END_DECLS
#endif /*CAIRO_SCRIPT_INTERPRETER_H*/

View file

@ -502,8 +502,10 @@ csi_string_new (csi_t *ctx,
ctx->free_string = NULL;
}
memcpy (string->string, str, len);
string->string[len] = '\0';
if (str != NULL) {
memcpy (string->string, str, len);
string->string[len] = '\0';
}
string->len = len;
string->base.type = CSI_OBJECT_TYPE_STRING;
@ -555,7 +557,7 @@ _csi_string_execute (csi_t *ctx, csi_string_t *string)
if (_csi_unlikely (status))
return status;
status = _csi_scan_file (ctx, &ctx->scanner, obj.datum.file);
status = _csi_scan_file (ctx, obj.datum.file);
csi_object_free (ctx, &obj);
return status;

View file

@ -5440,7 +5440,7 @@ _defs[] = {
{ "arc", _arc },
{ "arc-negative", _arc_negative },
{ "arc-", _arc_negative },
//{ "arc-to", NULL },
{ "arc-to", NULL },
{ "array", _array },
{ "astore", NULL },
{ "atan", NULL },

View file

@ -404,6 +404,7 @@ struct _csi_file {
PROCEDURE,
FILTER
} type;
unsigned int flags;
void *src;
void *data;
uint8_t *bp;
@ -426,14 +427,9 @@ struct _csi_scanner {
jmp_buf jmpbuf;
int depth;
enum {
NONE,
TOKEN,
COMMENT,
STRING,
HEX,
BASE85
} state;
csi_status_t (*push) (csi_t *ctx, csi_object_t *obj);
csi_status_t (*execute) (csi_t *ctx, csi_object_t *obj);
void *closure;
csi_buffer_t buffer;
csi_stack_t procedure_stack;
@ -478,6 +474,8 @@ struct _cairo_script_interpreter {
csi_dictionary_t *free_dictionary;
csi_string_t *free_string;
csi_operator_t opcode[256];
/* caches of live data */
csi_list_t *_images;
csi_list_t *_faces;
@ -505,6 +503,11 @@ csi_file_new (csi_t *ctx,
csi_object_t *obj,
const char *path, const char *mode);
csi_private csi_status_t
csi_file_new_for_stream (csi_t *ctx,
csi_object_t *obj,
FILE *stream);
csi_private csi_status_t
csi_file_new_for_bytes (csi_t *ctx,
csi_object_t *obj,
@ -803,7 +806,13 @@ csi_private csi_status_t
_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner);
csi_private csi_status_t
_csi_scan_file (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src);
_csi_scan_file (csi_t *ctx, csi_file_t *src);
csi_private csi_status_t
_csi_translate_file (csi_t *ctx,
csi_file_t *file,
cairo_write_func_t write_func,
void *closure);
csi_private void
_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner);

File diff suppressed because it is too large Load diff