Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4449231

Many JVMPI IDs lack defining event. JVM on startup should send them to Clients.

XMLWordPrintable

    • ladybird
    • generic
    • generic
    • Not verified

        This problem is reproducable only with the latest release (1.3.1-rc1) of hotspot JVM. It works as expected with Classic VM. From Incident Manager (Incident : 120869 ). See "Suggested Fix" and "Comments".

        Bug Description: The JVMPI spec
        (http://java.sun.com/j2se/1.3/docs/guide/jvmpi/jvmpi.html)
        states that: "Assuming the defining events are enabled during the
        profiler initialization, the profiler agent is guaranteed to be
        notified of an entity's creation through a defining event, before
        the entity appears in other JVMPI events. "

        However in 1.3.1RC1, both C1 and C2, it seems that many events
        during JVM startup are not sent, resulting in lots of undefined
        IDs for the JVMPI client, despite the defining events being enabled
        since JVM_OnLoad(). In fact, running with -verbose shows quite a
        bit of activity before JVM_OnLoad() is even called. This would
        appear to be a violation of the spec.

        Although we can request the defining events, this changes the model
        we are used to, and will have as-yet-unknown impact on our product
        because we will be receiving defining events at different times and
        in different contexts.

        The following fairly simple client demonstrates the problem with
        object IDs, but we also see it with class ids, and method ids in
        stack traces. The client tracks object IDs, and at JVM init time
        requests a heap dump (level 0). It walks the heap dump and prints
        out an error if it has not seen the ID. Errors will also be printed
        if, for instance, an object alloc event is sent with an arena ID
        for which there has been no defining event.

        Compile and run with "java -Xrunjvmpi_tool SomeClass" (SomeClass may
        even be bogus). Comapre the output with C1 or C2 (everything in the
        dump is unknown) versus the Classic VM (everything in the dump is
        known). There may be errors in the overall object tracking, I just
        whipped this up, but it seems correct for Classic so I doubt it's
        horribly wrong.

        Obviously, our real JVMPI client doesn't ask for a dump right at
        start up, but it does ask for regular stack traces and monitor
        dumps, and can ask for heap dumps at arbitrary time under user
        control.

        #include <stdio.h>
        #include <jvmpi.h>
         
        #define JVMPI(m) (jvmpi->m)
         
        struct obj_info {
                obj_info(JVMPI_Event * e) { init(e); }
                void init(JVMPI_Event * e);
                jobjectID id;
                obj_info * next;
                obj_info * prev;
                jint arena_id;
                obj_info * arena_next;
                obj_info * arena_prev;
        };
         
        obj_info * obj_list;
        obj_info * obj_free;
         
        struct arena_info {
                arena_info(jint id) { init(id); }
                void init(jint id);
                jint id;
                obj_info * head;
                arena_info * next;
                arena_info * prev;
        };
         
        arena_info * arena_list;
        arena_info * arena_free;

        void
        arena_info::init(jint arena_id)
        {
                id = arena_id;
                head = NULL;
                next = arena_list;
                prev = NULL;
                if (next) {
                        next->prev = this;
                }
                arena_list = this;
        }
         
        arena_info *
        find_arena(jint id)
        {
                arena_info * cur = arena_list;
                while (cur && cur->id != id) {
                        cur = cur->next;
                }
                return cur;
        }
         
        arena_info *
        new_arena(jint id)
        {
                arena_info * arena;
                if (arena_free) {
                        arena = arena_free;
                        arena_free = arena->next;
                        arena->init(id);
                } else {
                        arena = new arena_info(id);
                }
                return arena;
        }

        void
        arena_add(obj_info * obj)
        {
                arena_info * arena = find_arena(obj->arena_id);
                if (!arena) {
                        fprintf(stderr, "No arena %ld to add/move object %p
        to\n",
                                        (long)obj->arena_id, (void *)obj->id);
                        arena = new_arena(obj->arena_id);
                }
                obj->arena_prev = NULL;
                obj->arena_next = arena->head;
                if (obj->arena_next) {
                        obj->arena_next->prev = obj;
                }
                arena->head = obj;
        }
         
        void
        arena_delete_obj(obj_info * obj)
        {
                arena_info * arena = find_arena(obj->arena_id);
                if (arena) {
                        if (obj->arena_prev) {
                                obj->arena_prev->arena_next = obj->arena_next;
                        } else {
                                arena->head = obj->arena_next;
                        }
                        if (obj->arena_next) {
                                obj->arena_next->arena_prev = obj->arena_prev;
                        }
                }
        }

        void
        arena_move_obj(obj_info * obj, jint new_id)
        {
                arena_delete_obj(obj);
                obj->arena_id = new_id;
                arena_add(obj);
        }
        void
        obj_info::init(JVMPI_Event * e)
        {
                id = e->u.obj_alloc.obj_id;
                arena_id = e->u.obj_alloc.arena_id;
                next = obj_list;
                prev = NULL;
                arena_add(this);
                if (next) {
                        next->prev = this;
                }
                obj_list = this;
        }
         
        obj_info *
        find_obj(jobjectID id)
        {
                obj_info * cur = obj_list;
                while (cur && cur->id != id) {
                        cur = cur->next;
                }
                return cur;
        }

        void
        delete_obj(jobjectID id)
        {
                obj_info * obj = find_obj(id);
                if (!obj) {
                        fprintf(stderr, "Can't delete %p; no defining event\n",
        (void
        *)id);
                } else {
                        // Remove from object list
                        if (obj->prev) {
                                obj->prev->next = obj->next;
                        } else {
                                obj_list = obj->next;
                        }
                        if (obj->next) {
                                obj->next->prev = obj->prev;
                        }
                        // Remove from arena list
                        arena_delete_obj(obj);
                        // Add to free list
                        obj->next = obj_free;
                        obj_free = obj;
                }
        }
         
        void
        move_obj(jobjectID old_id, jobjectID new_id, jint new_arena)
        {
                obj_info * obj = find_obj(old_id);
                if (!obj) {
                        fprintf(stderr, "Can't move %p; no defining event\n",
        (void
        *)old_id);
                } else {
                        obj->id = new_id;
                        arena_move_obj(obj, new_arena);
                }
        }
        obj_info *
        add_obj(JVMPI_Event * e)
        {
                obj_info * obj = NULL;
                if (obj_free) {
                        obj = obj_free;
                        obj_free = obj_free->next;
                        obj->init(e);
                } else {
                        obj = new obj_info(e);
                }
                return obj;
        }
        void
        arena_delete(jint id)
        {
                arena_info * arena = find_arena(id);
                if (!arena) {
                        fprintf(stderr, "Cannot delete arena %ld; no defining
        event\n",
                                        (long)id);
                } else {
                        // Delete all objects
                        while (arena->head) {
                                delete_obj(arena->head->id);
                        }
                        // Remove from arena list
                        if (arena->prev) {
                                arena->prev->next = arena->next;
                        } else {
                                arena_list = arena->next;
                        }
                        if (arena->next) {
                                arena->next->prev = arena->prev;
                        }
                        // Add to free list
                        arena->next = arena_free;
                        arena_free = arena;
                }
        }

        void
        check_dump(char * begin, void * end)
        {
                int total = 0;
                int bad = 0;
                jobjectID id;
                obj_info * obj;
                while (begin + 1 + sizeof(jobjectID) <= end) {
                        memcpy((void *)&id, begin + 1, sizeof(jobjectID));
                        begin += 1 + sizeof(jobjectID);
                        ++total;
                        if (find_obj(id) == NULL) {
                                ++bad;
                                fprintf(stderr, "Unknown object %p in heap
        dump\n",
        (void *)id);
                        }
                }
                if (begin < end) {
                        fprintf(stderr, "Incomplete record at end of heap dump:
        %p -
        %p\n",
                                        (void *)begin, (void *)end);
                }
                printf("\nHeap dump had %d objects, %d bad\n", total, bad);
        }
         
        JVMPI_RawMonitor obj_lock;
         
        static JVMPI_Interface *jvmpi;
        static void notify(JVMPI_Event *);

        extern "C" JNIEXPORT jint JNICALL
        JVM_OnLoad(JavaVM *jvm, char *options, void *reserved)
        {
                int res = jvm->GetEnv((void **)&jvmpi, JVMPI_VERSION_1);
         
                if (res < 0) {
                        return JNI_ERR;
                }
         
                jvmpi->NotifyEvent = notify;
         
                JVMPI(EnableEvent)(JVMPI_EVENT_JVM_INIT_DONE, NULL);
                JVMPI(EnableEvent)(JVMPI_EVENT_JVM_SHUT_DOWN, NULL);
                JVMPI(EnableEvent)(JVMPI_EVENT_ARENA_NEW, NULL);
                JVMPI(EnableEvent)(JVMPI_EVENT_ARENA_DELETE, NULL);
                JVMPI(EnableEvent)(JVMPI_EVENT_OBJECT_ALLOC, NULL);
                JVMPI(EnableEvent)(JVMPI_EVENT_OBJECT_MOVE, NULL);
                JVMPI(EnableEvent)(JVMPI_EVENT_OBJECT_FREE, NULL);
                JVMPI(EnableEvent)(JVMPI_EVENT_GC_START, NULL);
                JVMPI(EnableEvent)(JVMPI_EVENT_GC_FINISH, NULL);
               
                obj_lock = JVMPI(RawMonitorCreate)("Object info lock");

                return JNI_OK;
        }

        static JVMPI_HeapDumpArg dump_arg = { JVMPI_DUMP_LEVEL_0 };

        void notify(JVMPI_Event * event)
        {
                switch (event->event_type) {
                case JVMPI_EVENT_JVM_INIT_DONE:
                        JVMPI(RequestEvent)(JVMPI_EVENT_HEAP_DUMP, (void *)&dump_arg);
                        break;
                case JVMPI_EVENT_JVM_SHUT_DOWN:
                        putchar('\n');
                        break;
                case JVMPI_EVENT_ARENA_NEW:
                        JVMPI(RawMonitorEnter)(obj_lock);
                        printf("\nNew arena %ld\n", (long)event->u.new_arena.arena_id);
                        new_arena(event->u.new_arena.arena_id);
                        JVMPI(RawMonitorExit)(obj_lock);
                        break;
                case JVMPI_EVENT_ARENA_DELETE:
                        JVMPI(RawMonitorEnter)(obj_lock);
                        printf("\nDelete arena %ld\n", (long)event->u.delete_arena.arena
        _id);
                        arena_delete(event->u.delete_arena.arena_id);
                        JVMPI(RawMonitorExit)(obj_lock);
                        break;
                case JVMPI_EVENT_OBJECT_ALLOC:
                        JVMPI(RawMonitorEnter)(obj_lock);
                        putchar('+');
                        add_obj(event);
                        JVMPI(RawMonitorExit)(obj_lock);
                        break;
                case JVMPI_EVENT_GC_START:
                        JVMPI(RawMonitorEnter)(obj_lock);
                        puts("\nGC Start:\n");
                        break;
                case JVMPI_EVENT_OBJECT_MOVE:
                        putchar('~');
                        move_obj(event->u.obj_move.obj_id, event->u.obj_move.new_obj_id,
                                        event->u.obj_move.new_arena_id);
                        break;
                case JVMPI_EVENT_OBJECT_FREE:
                        delete_obj(event->u.obj_free.obj_id);
                        putchar('-');
                        break;
                case JVMPI_EVENT_GC_FINISH:
                        puts("\nGC finish\n");
                        JVMPI(RawMonitorExit)(obj_lock);
                        break;
                case JVMPI_REQUESTED_EVENT|JVMPI_EVENT_HEAP_DUMP:
                        JVMPI(RawMonitorEnter)(obj_lock);
                        check_dump(event->u.heap_dump.begin, event->u.heap_dump.end);
                        JVMPI(RawMonitorExit)(obj_lock);
                        break;
                default:
                        break;
                }
        }

              mchung Mandy Chung
              rverabel Raghu Verabelli (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: