~ubuntu-branches/debian/squeeze/erlang/squeeze

« back to all changes in this revision

Viewing changes to erts/emulator/beam/erl_trace.c

  • Committer: Bazaar Package Importer
  • Author(s): Sergei Golovan
  • Date: 2009-02-15 16:42:52 UTC
  • mfrom: (1.1.13 upstream)
  • Revision ID: james.westby@ubuntu.com-20090215164252-dxpjjuq108nz4noa
Tags: 1:12.b.5-dfsg-2
Upload to unstable after lenny is released.

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
#include "dist.h"
33
33
#include "beam_bp.h"
34
34
#include "error.h"
 
35
#include "erl_binary.h"
 
36
#include "erl_bits.h"
35
37
 
36
38
#if 0
37
39
#define DEBUG_PRINTOUTS
675
677
    return hp+5;
676
678
}
677
679
 
 
680
static ERTS_INLINE void
 
681
send_to_tracer(Process *tracee,
 
682
               ERTS_TRACER_REF_TYPE tracer_ref,
 
683
               Eterm msg,
 
684
               Eterm **hpp,
 
685
               ErlHeapFragment *bp,
 
686
               int no_fake_sched)
 
687
{
 
688
    ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(tracee));
 
689
 
 
690
    erts_smp_mtx_lock(&smq_mtx);
 
691
 
 
692
    if (tracee->trace_flags & F_TIMESTAMP)
 
693
        *hpp = patch_ts(msg, *hpp);
 
694
 
 
695
    if (is_internal_pid(tracee->tracer_proc))
 
696
        ERTS_ENQ_TRACE_MSG(tracee->id, tracer_ref, msg, bp);
 
697
    else {
 
698
        ASSERT(is_internal_port(tracee->tracer_proc));
 
699
        send_to_port(no_fake_sched ? NULL : tracee,
 
700
                     msg,
 
701
                     &tracee->tracer_proc,
 
702
                     &tracee->trace_flags);
 
703
    }
 
704
 
 
705
    erts_smp_mtx_unlock(&smq_mtx);
 
706
 
 
707
}
 
708
 
 
709
static void
 
710
trace_sched_aux(Process *p, Eterm what, int never_fake_sched)
 
711
{
 
712
    Eterm local_heap[5+4+1+TS_HEAP_WORDS];
 
713
    Eterm tmp, mess, *hp;
 
714
    ErlHeapFragment *bp = NULL;
 
715
    ErlOffHeap *off_heap;
 
716
    ERTS_TRACER_REF_TYPE tracer_ref = ERTS_NULL_TRACER_REF;
 
717
    int sched_no, curr_func, to_port, no_fake_sched;
 
718
 
 
719
    if (is_nil(p->tracer_proc))
 
720
        return;
 
721
 
 
722
    no_fake_sched = never_fake_sched;
 
723
 
 
724
    switch (what) {
 
725
    case am_out:
 
726
    case am_out_exiting:
 
727
    case am_out_exited:
 
728
        no_fake_sched = 1;
 
729
        break;
 
730
    case am_in:
 
731
    case am_in_exiting:
 
732
        break;
 
733
    default:
 
734
        ASSERT(0);
 
735
        break;
 
736
    }
 
737
 
 
738
    sched_no = IS_TRACED_FL(p, F_TRACE_SCHED_NO);
 
739
    to_port = is_internal_port(p->tracer_proc);
 
740
 
 
741
    if (!to_port) {
 
742
        ASSERT(is_internal_pid(p->tracer_proc)
 
743
               && internal_pid_index(p->tracer_proc) < erts_max_processes);
 
744
 
 
745
        ERTS_GET_TRACER_REF(tracer_ref, p->tracer_proc, p->trace_flags);
 
746
    }
 
747
 
 
748
    if (ERTS_PROC_IS_EXITING(p)
 
749
#ifndef ERTS_SMP
 
750
        || p->status == P_FREE
 
751
#endif
 
752
        ) {
 
753
        curr_func = 0;
 
754
    }
 
755
    else {
 
756
        if (!p->current)
 
757
            p->current = find_function_from_pc(p->i);
 
758
        curr_func = p->current != NULL;
 
759
    }
 
760
 
 
761
    if (to_port)
 
762
        hp = &local_heap[0];
 
763
    else {
 
764
        Uint size = 5;
 
765
        if (curr_func)
 
766
            size += 4;
 
767
        if (sched_no)
 
768
            size += 1;
 
769
        size += TS_SIZE(p);
 
770
        hp = ERTS_ALLOC_SYSMSG_HEAP(size, &bp, &off_heap, tracer_ref);
 
771
    }
 
772
 
 
773
    if (!curr_func) {
 
774
        tmp = make_small(0);
 
775
    } else {
 
776
        tmp = TUPLE3(hp,p->current[0],p->current[1],make_small(p->current[2]));
 
777
        hp += 4;
 
778
    }
 
779
 
 
780
    if (!sched_no) {
 
781
        mess = TUPLE4(hp, am_trace, p->id, what, tmp);
 
782
        hp += 5;
 
783
    }
 
784
    else {
 
785
#ifdef ERTS_SMP
 
786
        Eterm sched_id = make_small(p->scheduler_data->no);
 
787
#else
 
788
        Eterm sched_id = make_small(1);
 
789
#endif
 
790
        mess = TUPLE5(hp, am_trace, p->id, what, sched_id, tmp);
 
791
        hp += 6;
 
792
    }
 
793
 
 
794
    send_to_tracer(p, tracer_ref, mess, &hp, bp, no_fake_sched);
 
795
}
 
796
 
678
797
/* Send {trace_ts, Pid, What, {Mod, Func, Arity}, Timestamp}
679
798
 * or   {trace, Pid, What, {Mod, Func, Arity}}
680
799
 *
681
 
 * where 'What' is supposed to be 'in' or 'out'.
 
800
 * where 'What' is supposed to be 'in', 'out', 'in_exiting',
 
801
 * 'out_exiting', or 'out_exited'.
682
802
 */
683
803
void
684
804
trace_sched(Process *p, Eterm what)
685
805
{
686
 
    Eterm tmp;
687
 
    Eterm mess;
688
 
    Eterm* hp;
689
 
    int ws = 5; 
690
 
    Eterm sched_id;
691
 
 
692
 
    if (is_internal_port(p->tracer_proc)) {
693
 
        Eterm local_heap[4+5+6];
694
 
        hp = local_heap;
695
 
 
696
 
        if (p->current == NULL) {
697
 
            p->current = find_function_from_pc(p->i);
698
 
        }
699
 
        if (p->current == NULL) {
700
 
            tmp = make_small(0);
701
 
        } else {
702
 
            tmp = TUPLE3(hp, p->current[0], p->current[1], make_small(p->current[2]));
703
 
            hp += 4;
704
 
        }
705
 
        
706
 
        if (IS_TRACED_FL(p, F_TRACE_SCHED_NO)) {
707
 
#ifdef ERTS_SMP
708
 
                if (p->scheduler_data) sched_id = make_small(p->scheduler_data->no);
709
 
                else sched_id = am_undefined;
710
 
#else
711
 
                sched_id = make_small(1);
712
 
#endif
713
 
                mess = TUPLE5(hp, am_trace, p->id, what, sched_id, tmp);
714
 
                ws = 6;
715
 
        } else {
716
 
                mess = TUPLE4(hp, am_trace, p->id, what, tmp);
717
 
                ws = 5;
718
 
        }
719
 
        
720
 
        hp += ws;
721
 
                
722
 
        
723
 
        erts_smp_mtx_lock(&smq_mtx);
724
 
        if (p->trace_flags & F_TIMESTAMP) {
725
 
            hp = patch_ts(mess, hp);
726
 
        }
727
 
        if (what != am_out) {
728
 
            send_to_port(p, mess, &p->tracer_proc, &p->trace_flags);
729
 
        } else {
730
 
            send_to_port(NULL, mess, &p->tracer_proc, &p->trace_flags);
731
 
        }
732
 
        erts_smp_mtx_unlock(&smq_mtx);
733
 
    } else {
734
 
        ErlHeapFragment *bp;
735
 
        ErlOffHeap *off_heap;
736
 
        ERTS_TRACER_REF_TYPE tracer_ref;
737
 
 
738
 
        ASSERT(is_internal_pid(p->tracer_proc)
739
 
               && internal_pid_index(p->tracer_proc) < erts_max_processes);
740
 
 
741
 
        ERTS_GET_TRACER_REF(tracer_ref, p->tracer_proc, p->trace_flags);
742
 
 
743
 
        hp = ERTS_ALLOC_SYSMSG_HEAP(4 + ws + TS_SIZE(p), &bp, &off_heap, tracer_ref);
744
 
        
745
 
        if (p->current == NULL) {
746
 
            p->current = find_function_from_pc(p->i);
747
 
        }
748
 
        if (p->current == NULL) {
749
 
            tmp = make_small(0);
750
 
        } else {
751
 
            tmp = TUPLE3(hp, p->current[0], p->current[1], make_small(p->current[2]));
752
 
            hp += 4;
753
 
        }
754
 
        
755
 
        if (IS_TRACED_FL(p, F_TRACE_SCHED_NO)) {
756
 
#ifdef ERTS_SMP
757
 
                if (p->scheduler_data) sched_id = make_small(p->scheduler_data->no);
758
 
                else sched_id = make_small(am_undefined);
759
 
#else
760
 
                sched_id = make_small(1);
761
 
#endif
762
 
                mess = TUPLE5(hp, am_trace,p->id/* Local pid */, what, sched_id, tmp);
763
 
                ws = 6;
764
 
        } else {
765
 
                mess = TUPLE4(hp, am_trace, p->id, what, tmp);
766
 
                ws = 5;
767
 
        }
768
 
        hp += ws;
769
 
 
770
 
        erts_smp_mtx_lock(&smq_mtx);
771
 
 
772
 
        if (p->trace_flags & F_TIMESTAMP) {
773
 
            hp = patch_ts(mess, hp);
774
 
        }
775
 
 
776
 
        ERTS_ENQ_TRACE_MSG(p->id, tracer_ref, mess, bp);
777
 
        erts_smp_mtx_unlock(&smq_mtx);
778
 
    }
 
806
    trace_sched_aux(p, what, 0);
779
807
}
780
808
 
781
 
 
782
809
/* Send {trace_ts, Pid, Send, Msg, DestPid, Timestamp}
783
810
 * or   {trace, Pid, Send, Msg, DestPid}
784
811
 *
1445
1472
#ifdef ERTS_SMP
1446
1473
    Eterm tracee;
1447
1474
#endif
1448
 
    
 
1475
    Eterm transformed_args[MAX_ARG];
 
1476
    ErlSubBin sub_bin_heap;
 
1477
 
1449
1478
    ASSERT(tracer_pid);
1450
1479
    if (*tracer_pid == am_true) {
1451
1480
        /* Breakpoint trace enabled without specifying tracer =>
1488
1517
#endif
1489
1518
    }
1490
1519
 
 
1520
    /*
 
1521
     * Because of the delayed sub-binary creation optimization introduced in
 
1522
     * R12B, (at most) one of arguments can be a match context instead of
 
1523
     * a binary. Since we don't want to handle match contexts in utility functions
 
1524
     * such as size_object() and copy_struct(), we must make sure that we
 
1525
     * temporarily convert any match contexts to sub binaries.
 
1526
     */
 
1527
    arity = mfa[2];
 
1528
#ifdef DEBUG
 
1529
    sub_bin_heap.thing_word = 0;
 
1530
#endif
 
1531
    for (i = 0; i < arity; i++) {
 
1532
        Eterm arg = args[i];
 
1533
        if (is_boxed(arg) && header_is_bin_matchstate(*boxed_val(arg))) {
 
1534
            ErlBinMatchState* ms = (ErlBinMatchState *) boxed_val(arg);
 
1535
            ErlBinMatchBuffer* mb = &ms->mb;
 
1536
            ErlSubBin* sb = &sub_bin_heap;
 
1537
            Uint bit_size;
 
1538
 
 
1539
            ASSERT(sub_bin_heap.thing_word == 0); /* At most one of match context */
 
1540
 
 
1541
            bit_size = mb->size - mb->offset;
 
1542
            sb->thing_word = HEADER_SUB_BIN;
 
1543
            sb->size = BYTE_OFFSET(bit_size);
 
1544
            sb->bitsize = BIT_OFFSET(bit_size);
 
1545
            sb->offs = BYTE_OFFSET(mb->offset);
 
1546
            sb->bitoffs = BIT_OFFSET(mb->offset);
 
1547
            sb->is_writable = 0;
 
1548
            sb->orig = mb->orig;
 
1549
 
 
1550
            arg = make_binary(sb);
 
1551
        }
 
1552
        transformed_args[i] = arg;
 
1553
    }
 
1554
    args = transformed_args;
 
1555
 
1491
1556
    if (is_internal_port(*tracer_pid)) {
1492
1557
        Eterm local_heap[64+MAX_ARG];
1493
1558
        hp = local_heap;
1525
1590
        
1526
1591
        /* BEGIN this code should be the same for port and pid trace */
1527
1592
        return_flags = 0;
1528
 
        arity = mfa[2];
1529
1593
        if (match_spec) {
1530
1594
            pam_result = erts_match_set_run(p, match_spec, args, arity,
1531
1595
                                            &return_flags);
1601
1665
        Eterm tpid;
1602
1666
#endif
1603
1667
        unsigned size;
1604
 
        unsigned sizes[256];
 
1668
        unsigned sizes[MAX_ARG];
1605
1669
        unsigned pam_result_size = 0;
1606
1670
        int invalid_tracer;
1607
1671
#ifdef DEBUG
1652
1716
        
1653
1717
        /* BEGIN this code should be the same for port and pid trace */
1654
1718
        return_flags = 0;
1655
 
        arity = mfa[2];
1656
1719
        if (match_spec) {
1657
1720
            pam_result = erts_match_set_run(p, match_spec, args, arity,
1658
1721
                                            &return_flags);
2003
2066
         * they usually appear in normal code... */
2004
2067
        if (is_non_value(result)) {
2005
2068
            Uint reason = p->freason;
2006
 
            if (reason != TRAP && reason != RESCHEDULE) {
 
2069
            if (reason != TRAP) {
2007
2070
                Eterm class;
2008
2071
                Eterm value = p->fvalue;
2009
2072
                Eterm nocatch[3];
2439
2502
 */
2440
2503
 
2441
2504
 
2442
 
void trace_virtual_sched(Process *p, Eterm what) {
2443
 
    Eterm tmp;
2444
 
    Eterm mess;
2445
 
    Eterm* hp;
2446
 
    Eterm sched_id = am_undefined;
2447
 
    int ws_id = 6;
2448
 
 
2449
 
    if (is_internal_port(p->tracer_proc)) {
2450
 
        Eterm local_heap[4+5+6];
2451
 
        hp = local_heap;
2452
 
 
2453
 
        if (p->current == NULL) {
2454
 
            p->current = find_function_from_pc(p->i);
2455
 
        }
2456
 
        if (p->current == NULL) {
2457
 
            tmp = make_small(0);
2458
 
        } else {
2459
 
            tmp = TUPLE3(hp, p->current[0], p->current[1], make_small(p->current[2]));
2460
 
            hp += 4;
2461
 
        }
2462
 
        
2463
 
        if (IS_TRACED_FL(p, F_TRACE_SCHED_NO)) {
2464
 
#ifdef ERTS_SMP
2465
 
                if (p->scheduler_data) sched_id = make_small(p->scheduler_data->no);
2466
 
                else sched_id = am_undefined;
2467
 
#else
2468
 
                sched_id = make_small(1);
2469
 
#endif
2470
 
                mess = TUPLE5(hp, am_trace, p->id, what, sched_id, tmp);
2471
 
                ws_id = 6;
2472
 
        } else {
2473
 
                mess = TUPLE4(hp, am_trace, p->id, what, tmp);
2474
 
                ws_id = 5;
2475
 
        }
2476
 
        hp += ws_id;
2477
 
                
2478
 
        
2479
 
        erts_smp_mtx_lock(&smq_mtx);
2480
 
        if (p->trace_flags & F_TIMESTAMP) {
2481
 
            hp = patch_ts(mess, hp);
2482
 
        }
2483
 
        send_to_port(NULL, mess, &p->tracer_proc, &p->trace_flags);
2484
 
        erts_smp_mtx_unlock(&smq_mtx);
2485
 
    } else {
2486
 
        ErlHeapFragment *bp;
2487
 
        ErlOffHeap *off_heap;
2488
 
        ERTS_TRACER_REF_TYPE tracer_ref;
2489
 
        ASSERT(is_internal_pid(p->tracer_proc)
2490
 
               && internal_pid_index(p->tracer_proc) < erts_max_processes);
2491
 
 
2492
 
        if (IS_TRACED_FL(p, F_TRACE_SCHED_NO)) ws_id = 6; /* Make place for scheduler id */
2493
 
 
2494
 
        ERTS_GET_TRACER_REF(tracer_ref, p->tracer_proc, p->trace_flags);
2495
 
 
2496
 
        hp = ERTS_ALLOC_SYSMSG_HEAP(ws_id + 4 + TS_SIZE(p),
2497
 
                                    &bp,
2498
 
                                    &off_heap,
2499
 
                                    tracer_ref);
2500
 
        
2501
 
        if (p->current == NULL) {
2502
 
            p->current = find_function_from_pc(p->i);
2503
 
        }
2504
 
        if (p->current == NULL) {
2505
 
            tmp = make_small(0);
2506
 
        } else {
2507
 
            tmp = TUPLE3(hp, p->current[0], p->current[1], make_small(p->current[2]));
2508
 
            hp += 4;
2509
 
        }
2510
 
        
2511
 
        if (IS_TRACED_FL(p, F_TRACE_SCHED_NO)) {
2512
 
#ifdef ERTS_SMP
2513
 
                if (p->scheduler_data) sched_id = make_small(p->scheduler_data->no);
2514
 
                else sched_id = am_undefined;
2515
 
#else
2516
 
                sched_id = make_small(1);
2517
 
#endif
2518
 
                mess = TUPLE5(hp, am_trace,p->id/* Local pid */, what, sched_id, tmp);
2519
 
        } else {
2520
 
                mess = TUPLE4(hp, am_trace, p->id, what, tmp);
2521
 
        }
2522
 
        
2523
 
        hp += ws_id;
2524
 
 
2525
 
        erts_smp_mtx_lock(&smq_mtx);
2526
 
 
2527
 
        if (p->trace_flags & F_TIMESTAMP) {
2528
 
            hp = patch_ts(mess, hp);
2529
 
        }
2530
 
 
2531
 
        ERTS_ENQ_TRACE_MSG(p->id, tracer_ref, mess, bp);
2532
 
        erts_smp_mtx_unlock(&smq_mtx);
2533
 
    }
 
2505
void trace_virtual_sched(Process *p, Eterm what)
 
2506
{
 
2507
    trace_sched_aux(p, what, 1);
2534
2508
}
2535
2509
 
2536
2510
/* Port profiling */