[svn:parrot] r47963 - in branches/gsoc_instrument: . examples/library src/dynpmc t/dynpmc

khairul at svn.parrot.org khairul at svn.parrot.org
Fri Jul 2 16:29:57 UTC 2010


Author: khairul
Date: Fri Jul  2 16:29:56 2010
New Revision: 47963
URL: https://trac.parrot.org/parrot/changeset/47963

Log:
Added tests for InstrumentGC.

Added:
   branches/gsoc_instrument/t/dynpmc/instrumentgc.t   (contents, props changed)
Modified:
   branches/gsoc_instrument/MANIFEST
   branches/gsoc_instrument/examples/library/tracer.nqp
   branches/gsoc_instrument/src/dynpmc/instrumentgc.pmc
   branches/gsoc_instrument/src/dynpmc/instrumentpmc.pmc

Modified: branches/gsoc_instrument/MANIFEST
==============================================================================
--- branches/gsoc_instrument/MANIFEST	Fri Jul  2 14:05:56 2010	(r47962)
+++ branches/gsoc_instrument/MANIFEST	Fri Jul  2 16:29:56 2010	(r47963)
@@ -1684,6 +1684,7 @@
 t/dynpmc/foo2.t                                             [test]
 t/dynpmc/gziphandle.t                                       [test]
 t/dynpmc/instrument.t                                       [test]
+t/dynpmc/instrumentgc.t                                     [test]
 t/dynpmc/instrumentop.t                                     [test]
 t/dynpmc/os.t                                               [test]
 t/dynpmc/pccmethod_test.t                                   [test]

Modified: branches/gsoc_instrument/examples/library/tracer.nqp
==============================================================================
--- branches/gsoc_instrument/examples/library/tracer.nqp	Fri Jul  2 14:05:56 2010	(r47962)
+++ branches/gsoc_instrument/examples/library/tracer.nqp	Fri Jul  2 16:29:56 2010	(r47963)
@@ -14,6 +14,8 @@
 
 % ./parrot-nqp examples/library/tracer.nqp <file>
 
+=cut
+
 =end
 
 Q:PIR {

Modified: branches/gsoc_instrument/src/dynpmc/instrumentgc.pmc
==============================================================================
--- branches/gsoc_instrument/src/dynpmc/instrumentgc.pmc	Fri Jul  2 14:05:56 2010	(r47962)
+++ branches/gsoc_instrument/src/dynpmc/instrumentgc.pmc	Fri Jul  2 16:29:56 2010	(r47963)
@@ -118,6 +118,7 @@
     ATTR Hash                          *stub_hash;
     ATTR Hash                          *original_hash;
     ATTR Hash                          *entry_hash;
+    ATTR PMC                           *hook_count;
 
 /*
 
@@ -154,6 +155,7 @@
         attr->instrument      = instrument;
         attr->gc_original     = supervised->gc_sys;
         attr->gc_instrumented = mem_gc_allocate_zeroed_typed(INTERP, InstrumentGC_Subsystem);
+        attr->hook_count      = Parrot_pmc_new(INTERP, enum_class_Hash);
 
         /* Initiliase the instrumented gc_sys with the original values. */
         attr->gc_instrumented->instrument_gc = SELF;
@@ -216,18 +218,27 @@
 
         iter = VTABLE_get_iter(INTERP, list);
         while (VTABLE_get_bool(INTERP, iter)) {
+            INTVAL count;
             PMC *item_pmc = VTABLE_shift_pmc(INTERP, iter);
             STRING *item  = VTABLE_get_string(INTERP, item_pmc);
             size_t **entry, *func;
 
-            /* Replace the entry with the stub. */
-            entry = (size_t **) parrot_hash_get(INTERP, attr->entry_hash, item);
-            func  = (size_t *)  parrot_hash_get(INTERP, attr->stub_hash, item);
-            if (entry == NULL || func == NULL) {
-                Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
-                                            "Unknown GC function: %Ss", item);
+            /* Check if the entry has already been instrumented. */
+            count = VTABLE_get_integer_keyed_str(INTERP, attr->hook_count, item);
+            if (count == 0) {
+                /* Replace the entry with the stub. */
+                entry = (size_t **) parrot_hash_get(INTERP, attr->entry_hash, item);
+                func  = (size_t *)  parrot_hash_get(INTERP, attr->stub_hash, item);
+                if (entry == NULL || func == NULL) {
+                    Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
+                                                "Unknown GC function: %Ss", item);
+                }
+                *entry = func;
             }
-            *entry = func;
+
+            /* Update the count. */
+            count++;
+            VTABLE_set_integer_keyed_str(INTERP, attr->hook_count, item, count);
         }
     }
 
@@ -253,19 +264,62 @@
 
         iter = VTABLE_get_iter(INTERP, list);
         while (VTABLE_get_bool(INTERP, iter)) {
+            INTVAL count;
             PMC *item_pmc = VTABLE_shift_pmc(INTERP, iter);
             STRING *item  = VTABLE_get_string(INTERP, item_pmc);
             size_t **entry, *func;
 
-            /* Simply replace the stub with the original entry. */
-            entry = (size_t **) parrot_hash_get(INTERP, attr->entry_hash, item);
-            func  = (size_t *)  parrot_hash_get(INTERP, attr->original_hash, item);
-            if (entry == NULL || func == NULL) {
+            /* Only remove the stub if request count == 1 => Last request. */
+            count = VTABLE_get_integer_keyed_str(INTERP, attr->hook_count, item);
+            if (count <= 0) {
+                /* Tried to remove 1 time too many. */
                 Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
-                                            "Unknown GC function: %Ss", item);
+                                            "GC function %Ss is not instrumented.", item);
+            }
+            else if (count == 1) {
+                /* Simply replace the stub with the original entry. */
+                entry = (size_t **) parrot_hash_get(INTERP, attr->entry_hash, item);
+                func  = (size_t *)  parrot_hash_get(INTERP, attr->original_hash, item);
+                if (entry == NULL || func == NULL) {
+                    Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
+                                                "Unknown GC function: %Ss", item);
+                }
+                *entry = func;
+            }
+
+            /* Update the count. */
+            count--;
+            VTABLE_set_integer_keyed_str(INTERP, attr->hook_count, item, count);
+        }
+    }
+
+/*
+
+=item C<PMC* get_instrumented_list()>
+
+Returns a ResizableStringArray PMC filled with
+the names of the gc entries that has been instrumented.
+
+=cut
+
+*/
+
+    METHOD get_instrumented_list() {
+        PMC *ret = Parrot_pmc_new(INTERP, enum_class_ResizableStringArray);
+        PMC *iter, *hook_hash;
+
+        GETATTR_InstrumentGC_hook_count(INTERP, SELF, hook_hash);
+        iter = VTABLE_get_iter(INTERP, hook_hash);
+
+        while (VTABLE_get_bool(INTERP, iter)) {
+            PMC *key     = VTABLE_shift_pmc(INTERP, iter);
+            INTVAL count = VTABLE_get_integer_keyed(INTERP, hook_hash, key);
+            if (count > 0) {
+                VTABLE_push_pmc(INTERP, ret, key);
             }
-            *entry = func;
         }
+
+        RETURN(PMC *ret);
     }
 
 /*
@@ -327,10 +381,20 @@
         else {
             /* Convert name to a constant string since we use the address of the
                constant string as the key to the various hashes. */
+            size_t *check;
+            Hash *stub_hash;
             char *c_str     = Parrot_str_to_cstring(INTERP, name);
             STRING *con_str = CONST_STRING(INTERP, c_str);
             VTABLE_push_string(INTERP, list, con_str);
             Parrot_free_cstring(c_str);
+
+            /* Ensure that con_str is the name of a hook. */
+            GETATTR_InstrumentGC_stub_hash(INTERP, SELF, stub_hash);
+            check = (size_t *) parrot_hash_get(INTERP, stub_hash, con_str);
+            if (check == NULL) {
+                Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
+                                            "Unknown GC function: %Ss", con_str);
+            }
         }
 
         RETURN(PMC *list);

Modified: branches/gsoc_instrument/src/dynpmc/instrumentpmc.pmc
==============================================================================
--- branches/gsoc_instrument/src/dynpmc/instrumentpmc.pmc	Fri Jul  2 14:05:56 2010	(r47962)
+++ branches/gsoc_instrument/src/dynpmc/instrumentpmc.pmc	Fri Jul  2 16:29:56 2010	(r47963)
@@ -13,7 +13,6 @@
 
 =head2 Methods
 
-=over 4
 
 =cut
 

Added: branches/gsoc_instrument/t/dynpmc/instrumentgc.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ branches/gsoc_instrument/t/dynpmc/instrumentgc.t	Fri Jul  2 16:29:56 2010	(r47963)
@@ -0,0 +1,414 @@
+#!./parrot
+# Copyright (C) 2010, Parrot Foundation.
+# $Id$
+
+=head1 NAME
+
+t/dynpmc/instrumentgc.t - test the InstrumentGC dynpmc
+
+=head1 SYNOPSIS
+
+        % prove t/dynpmc/instrumentGC.t
+
+=head1 DESCRIPTION
+
+Tests the gc notification interface provided by the InstrumentGC.pmc.
+
+=cut
+
+.include 'call_bits.pasm'
+.loadlib 'os'
+
+.sub main :main
+    .include 'test_more.pir'
+
+    # Load the Instrument library.
+    load_bytecode 'Instrument/InstrumentLib.pbc'
+
+    plan(29)
+
+    setup()
+    test_get_groups()
+    test_insert_hooks()
+    test_remove_hooks()
+    test_sample_notification()
+    cleanup()
+
+    .return()
+.end
+
+
+.sub setup
+    # Set up the GC function groups.
+    .local pmc groups
+    groups = new ['Hash']
+
+    # allocate.
+    $P0 = new ['ResizableStringArray']
+    push $P0, 'allocate_pmc_header'
+    push $P0, 'allocate_string_header'
+    push $P0, 'allocate_bufferlike_header'
+    push $P0, 'allocate_pmc_attributes'
+    push $P0, 'allocate_string_storage'
+    push $P0, 'allocate_buffer_storage'
+    push $P0, 'allocate_fixed_size_storage'
+    push $P0, 'allocate_memory_chunk'
+    push $P0, 'allocate_memory_chunk_with_interior_pointers'
+    groups['allocate'] = $P0
+
+    # reallocate.
+    $P0 = new ['ResizableStringArray']
+    push $P0, 'reallocate_string_storage'
+    push $P0, 'reallocate_buffer_storage'
+    push $P0, 'reallocate_memory_chunk'
+    push $P0, 'reallocate_memory_chunk_with_interior_pointers'
+    groups['reallocate'] = $P0
+
+    # free.
+    $P0 = new ['ResizableStringArray']
+    push $P0, 'free_pmc_header'
+    push $P0, 'free_string_header'
+    push $P0, 'free_bufferlike_header'
+    push $P0, 'free_pmc_attributes'
+    push $P0, 'free_fixed_size_storage'
+    push $P0, 'free_memory_chunk'
+    groups['free'] = $P0
+
+    # administration.
+    $P0 = new ['ResizableStringArray']
+    push $P0, 'finalize_gc_system'
+    push $P0, 'destroy_child_interp'
+    push $P0, 'do_gc_mark'
+    push $P0, 'compact_string_pool'
+    push $P0, 'mark_special'
+    push $P0, 'pmc_needs_early_collection'
+    push $P0, 'init_pool'
+    push $P0, 'block_mark'
+    push $P0, 'unblock_mark'
+    push $P0, 'block_sweep'
+    push $P0, 'unblock_sweep'
+    groups['administration'] = $P0
+
+    # Set groups as global.
+    set_global '%gc_groups', groups
+
+    # Create a simple program to test that events are raised.
+    .local string program
+    program = <<'PROG'
+.loadlib 'os'
+.sub main :main
+    $P0 = new ['OS']
+    $P0 = new ['Undef']
+    sweep 1
+    collect
+.end
+PROG
+
+    # Write to file.
+    .local pmc fh
+    fh = new ['FileHandle']
+    fh.'open'('t/dynpmc/instrumentgc-test1.pir', 'w')
+    fh.'puts'(program)
+    fh.'close'()
+.end
+
+.sub cleanup
+    # Remove the op test program.
+    .local pmc os
+    os = new ['OS']
+    os.'rm'('t/dynpmc/instrumentgc-test1.pir')
+.end
+
+.sub test_get_groups
+    # Ensure that the list of function names
+    #  returned for a group matches what it is supposed to return.
+    .local pmc groups, gc, instr
+
+    instr = new ['Instrument']
+    gc    = instr['gc']
+
+    # Setup the lists.
+    groups = get_global '%gc_groups'
+
+    # Test each group.
+    .local pmc group_iter, cur_group, cur_list, got_list
+    group_iter = iter groups
+    GROUP:
+      unless group_iter goto END_GROUP
+      cur_group = shift group_iter
+      $S0       = cur_group
+
+      cur_list  = groups[cur_group]
+      got_list  = gc.'get_hook_list'($S0)
+
+      # Check counts.
+      $I0  = cur_list
+      $I1  = got_list
+      $S1  = 'Group: Entry count matches for group '
+      $S1 .= $S0
+      is($I0, $I1, $S1)
+
+      # Check individual entry.
+      $I3 = is_same_set(cur_list, got_list)
+      $S1  = 'Group: Entries match for group '
+      $S1 .= $S0
+      is($I3, 1, $S1)
+
+      goto GROUP
+    END_GROUP:
+
+    # Test individual entry.
+    # Sample: allocate_pmc_header
+    $P0 = gc.'get_hook_list'('allocate_pmc_header')
+    $I0 = $P0
+    is($I0, 1, 'Individual: Entry count correct.')
+    $S0 = $P0[0]
+    is($S0, 'allocate_pmc_header', 'Individual: Entry listing correct.')
+
+    # Test non-existent individual entry.
+    # Sample: non-existent.
+    .local pmc eh
+    eh = new ['ExceptionHandler']
+    set_addr eh, NON_EXISTENT_OK
+    push_eh eh
+
+    $P0 = gc.'get_hook_list'('non-existent')
+
+    ok(0, 'Individual: Non-existent entry fail.')
+    goto NON_EXISTENT_END
+
+    NON_EXISTENT_OK:
+      ok(1, 'Individual: Non-existent entry ok.')
+
+    NON_EXISTENT_END:
+
+    #Done.
+.end
+
+.sub test_insert_hooks
+    .local pmc instr, gc, groups
+
+    instr  = new ['Instrument']
+    gc     = instr['gc']
+    groups = get_global '%gc_groups'
+
+    # Test inserting an individual hook.
+    # sample: allocate_pmc_header
+    gc.'insert_gc_hook'('allocate_pmc_header')
+    $P0 = gc.'get_instrumented_list'()
+    $I0 = $P0
+    is($I0, 1, 'Insert: Insert single hook count ok.')
+    $S0 = $P0[0]
+    is($S0, 'allocate_pmc_header', 'Insert: Insert single hook name ok.')
+
+    # Test inserting the same hook again.
+    gc.'insert_gc_hook'('allocate_pmc_header')
+    $P0 = gc.'get_instrumented_list'()
+    $I0 = $P0
+    is($I0, 1, 'Re-insert: Re-inserting single hook count ok.')
+    $S0 = $P0[0]
+    is($S0, 'allocate_pmc_header', 'Re-insert: Re-inserting single hook name ok.')
+
+    # Remove the hook before testing inserting groups.
+    gc.'remove_gc_hook'('allocate_pmc_header')
+    gc.'remove_gc_hook'('allocate_pmc_header')
+
+    # Test inserting a group of hooks.
+    # sample: free
+    gc.'insert_gc_hook'('free')
+    $P0 = gc.'get_instrumented_list'()
+    $P1 = groups['free']
+    $I0 = $P0
+    $I1 = $P1
+    is($I0, $I1, 'Insert group: Count ok.')
+    $I2 = is_same_set($P0, $P1)
+    is($I2, 1, 'Insert group: Names ok.')
+
+    # Test inserting a non-existent hook.
+    # sample: non-existent.
+    .local pmc eh
+    eh = new ['ExceptionHandler']
+    set_addr eh, NON_EXISTENT_OK
+    push_eh eh
+
+    gc.'insert_gc_hook'('non-existent')
+
+    ok(0, 'Insert: Non-existent entry fail.')
+    goto NON_EXISTENT_END
+
+    NON_EXISTENT_OK:
+      ok(1, 'Insert: Non-existent entry ok.')
+
+    NON_EXISTENT_END:
+
+    #Done
+.end
+
+.sub test_remove_hooks
+    .local pmc instr, gc, groups
+
+    instr  = new ['Instrument']
+    gc     = instr['gc']
+    groups = get_global '%gc_groups'
+
+    # Test removing an individual hook.
+    # sample: allocate_pmc_header
+    gc.'insert_gc_hook'('allocate_pmc_header')
+    gc.'remove_gc_hook'('allocate_pmc_header')
+    $P0 = gc.'get_instrumented_list'()
+    $I0 = $P0
+    is($I0, 0, 'Remove: Single hook removal ok.')
+
+    # Test insert 2 hooks, remove 1 hook.
+    # sample: allocate_pmc_header, free_pmc_header
+    gc.'insert_gc_hook'('allocate_pmc_header')
+    gc.'insert_gc_hook'('free_pmc_header')
+    gc.'remove_gc_hook'('free_pmc_header')
+    $P0 = gc.'get_instrumented_list'()
+    $I0 = $P0
+    is($I0, 1, 'Remove2: Removal count ok.')
+    $S0 = $P0[0]
+    is($S0, 'allocate_pmc_header', 'Remove2: Removal name ok.')
+    gc.'remove_gc_hook'('allocate_pmc_header')
+
+    # Test removing of groups.
+    # sample: allocate
+    gc.'insert_gc_hook'('allocate')
+    gc.'remove_gc_hook'('allocate')
+    $P0 = gc.'get_instrumented_list'()
+    $I0 = $P0
+    is($I0, 0, 'Remove Group: Removal ok.')
+
+    # Test removing a non-existent hook.
+    # sample: non-existent.
+    .local pmc eh
+    eh = new ['ExceptionHandler']
+    set_addr eh, NON_EXISTENT_OK
+    push_eh eh
+
+    gc.'remove_gc_hook'('non-existent')
+
+    ok(0, 'Remove: Non-existent removal fail.')
+    goto NON_EXISTENT_END
+
+    NON_EXISTENT_OK:
+      ok(1, 'Remove: Non-existent removal ok.')
+
+    NON_EXISTENT_END:
+
+    # Test removing a hook too many times.
+    # sample: non-existent.
+    eh = new ['ExceptionHandler']
+    set_addr eh, TOO_MANY_OK
+    push_eh eh
+
+    gc.'insert_gc_hook'('allocate_pmc_header')
+    gc.'remove_gc_hook'('allocate_pmc_header')
+    gc.'remove_gc_hook'('allocate_pmc_header')
+
+    ok(0, 'Remove: Too many removal fail.')
+    goto TOO_MANY_END
+
+    TOO_MANY_OK:
+      ok(1, 'Remove: Too many removal ok.')
+
+    TOO_MANY_END:
+
+    #Done
+.end
+
+.sub test_sample_notification
+    .local pmc instr, gc_event, args, gc_class
+
+    $S0  = 't/dynpmc/instrumentgc-test1.pir'
+    args = new ['ResizableStringArray']
+    push args, $S0
+
+    gc_class = get_hll_global ['Instrument';'Event'], 'GC'
+    gc_event = gc_class.'new'()
+    instr    = new ['Instrument']
+
+    # Test do_gc_mark
+    gc_event.'inspect'('do_gc_mark')
+    gc_event.'callback'('sample_notification_callback')
+
+    instr.'attach'(gc_event)
+    instr.'run'($S0, args)
+
+.end
+
+.sub sample_notification_callback
+    .param pmc data
+
+    # Event fired.
+    ok(1, 'Event: Event fired.')
+
+    ## Test the interesting bits.
+
+    # Test line.
+    $I0 = data['line']
+    is($I0, 5, 'Event: Line ok.')
+
+    # Test file.
+    $S0 = data['file']
+    is($S0, 't/dynpmc/instrumentgc-test1.pir', 'Event: File ok.')
+
+    # Test sub.
+    $S0 = data['sub']
+    is($S0, 'main', 'Event: Sub ok.')
+
+    # Test type.
+    $S0 = data['type']
+    is($S0, 'do_gc_mark', 'Event: Type ok.')
+.end
+
+# Helper sub: Check if 2 sets with unique items are the same.
+.sub is_same_set
+    .param pmc arr1
+    .param pmc arr2
+    .local pmc hash
+
+    $I0 = arr1
+    $I1 = arr2
+    if $I0 != $I1 goto NO
+
+    hash = new ['Hash']
+
+    # Build the comparison hash
+    $I3 = 0
+    INSERT_LOOP:
+      if $I3 >= $I0 goto END_INSERT_LOOP
+
+      $S0       = arr1[$I3]
+      hash[$S0] = 1
+
+      inc $I3
+      goto INSERT_LOOP
+    END_INSERT_LOOP:
+
+    # Check the contents of arr2
+    $I3 = 0
+    CHECK_LOOP:
+      if $I3 >= $I0 goto END_CHECK_LOOP
+
+      $S0 = arr2[$I3]
+      $I4 = exists hash[$S0]
+
+      if $I4 == 0 goto NO
+
+      inc $I3
+      goto CHECK_LOOP
+    END_CHECK_LOOP:
+
+    YES:
+      .return(1)
+
+    NO:
+      .return(0)
+.end
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:


More information about the parrot-commits mailing list