linux/tools/perf/util/thread-stack.c
<<
>>
Prefs
   1/*
   2 * thread-stack.c: Synthesize a thread's stack using call / return events
   3 * Copyright (c) 2014, Intel Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 */
  15
  16#include <linux/rbtree.h>
  17#include <linux/list.h>
  18#include <linux/log2.h>
  19#include <errno.h>
  20#include "thread.h"
  21#include "event.h"
  22#include "machine.h"
  23#include "util.h"
  24#include "debug.h"
  25#include "symbol.h"
  26#include "comm.h"
  27#include "call-path.h"
  28#include "thread-stack.h"
  29
  30#define STACK_GROWTH 2048
  31
  32/**
  33 * struct thread_stack_entry - thread stack entry.
  34 * @ret_addr: return address
  35 * @timestamp: timestamp (if known)
  36 * @ref: external reference (e.g. db_id of sample)
  37 * @branch_count: the branch count when the entry was created
  38 * @cp: call path
  39 * @no_call: a 'call' was not seen
  40 * @trace_end: a 'call' but trace ended
  41 */
  42struct thread_stack_entry {
  43        u64 ret_addr;
  44        u64 timestamp;
  45        u64 ref;
  46        u64 branch_count;
  47        struct call_path *cp;
  48        bool no_call;
  49        bool trace_end;
  50};
  51
  52/**
  53 * struct thread_stack - thread stack constructed from 'call' and 'return'
  54 *                       branch samples.
  55 * @stack: array that holds the stack
  56 * @cnt: number of entries in the stack
  57 * @sz: current maximum stack size
  58 * @trace_nr: current trace number
  59 * @branch_count: running branch count
  60 * @kernel_start: kernel start address
  61 * @last_time: last timestamp
  62 * @crp: call/return processor
  63 * @comm: current comm
  64 * @arr_sz: size of array if this is the first element of an array
  65 */
  66struct thread_stack {
  67        struct thread_stack_entry *stack;
  68        size_t cnt;
  69        size_t sz;
  70        u64 trace_nr;
  71        u64 branch_count;
  72        u64 kernel_start;
  73        u64 last_time;
  74        struct call_return_processor *crp;
  75        struct comm *comm;
  76        unsigned int arr_sz;
  77};
  78
  79/*
  80 * Assume pid == tid == 0 identifies the idle task as defined by
  81 * perf_session__register_idle_thread(). The idle task is really 1 task per cpu,
  82 * and therefore requires a stack for each cpu.
  83 */
  84static inline bool thread_stack__per_cpu(struct thread *thread)
  85{
  86        return !(thread->tid || thread->pid_);
  87}
  88
  89static int thread_stack__grow(struct thread_stack *ts)
  90{
  91        struct thread_stack_entry *new_stack;
  92        size_t sz, new_sz;
  93
  94        new_sz = ts->sz + STACK_GROWTH;
  95        sz = new_sz * sizeof(struct thread_stack_entry);
  96
  97        new_stack = realloc(ts->stack, sz);
  98        if (!new_stack)
  99                return -ENOMEM;
 100
 101        ts->stack = new_stack;
 102        ts->sz = new_sz;
 103
 104        return 0;
 105}
 106
 107static int thread_stack__init(struct thread_stack *ts, struct thread *thread,
 108                              struct call_return_processor *crp)
 109{
 110        int err;
 111
 112        err = thread_stack__grow(ts);
 113        if (err)
 114                return err;
 115
 116        if (thread->mg && thread->mg->machine)
 117                ts->kernel_start = machine__kernel_start(thread->mg->machine);
 118        else
 119                ts->kernel_start = 1ULL << 63;
 120        ts->crp = crp;
 121
 122        return 0;
 123}
 124
 125static struct thread_stack *thread_stack__new(struct thread *thread, int cpu,
 126                                              struct call_return_processor *crp)
 127{
 128        struct thread_stack *ts = thread->ts, *new_ts;
 129        unsigned int old_sz = ts ? ts->arr_sz : 0;
 130        unsigned int new_sz = 1;
 131
 132        if (thread_stack__per_cpu(thread) && cpu > 0)
 133                new_sz = roundup_pow_of_two(cpu + 1);
 134
 135        if (!ts || new_sz > old_sz) {
 136                new_ts = calloc(new_sz, sizeof(*ts));
 137                if (!new_ts)
 138                        return NULL;
 139                if (ts)
 140                        memcpy(new_ts, ts, old_sz * sizeof(*ts));
 141                new_ts->arr_sz = new_sz;
 142                zfree(&thread->ts);
 143                thread->ts = new_ts;
 144                ts = new_ts;
 145        }
 146
 147        if (thread_stack__per_cpu(thread) && cpu > 0 &&
 148            (unsigned int)cpu < ts->arr_sz)
 149                ts += cpu;
 150
 151        if (!ts->stack &&
 152            thread_stack__init(ts, thread, crp))
 153                return NULL;
 154
 155        return ts;
 156}
 157
 158static struct thread_stack *thread__cpu_stack(struct thread *thread, int cpu)
 159{
 160        struct thread_stack *ts = thread->ts;
 161
 162        if (cpu < 0)
 163                cpu = 0;
 164
 165        if (!ts || (unsigned int)cpu >= ts->arr_sz)
 166                return NULL;
 167
 168        ts += cpu;
 169
 170        if (!ts->stack)
 171                return NULL;
 172
 173        return ts;
 174}
 175
 176static inline struct thread_stack *thread__stack(struct thread *thread,
 177                                                    int cpu)
 178{
 179        if (!thread)
 180                return NULL;
 181
 182        if (thread_stack__per_cpu(thread))
 183                return thread__cpu_stack(thread, cpu);
 184
 185        return thread->ts;
 186}
 187
 188static int thread_stack__push(struct thread_stack *ts, u64 ret_addr,
 189                              bool trace_end)
 190{
 191        int err = 0;
 192
 193        if (ts->cnt == ts->sz) {
 194                err = thread_stack__grow(ts);
 195                if (err) {
 196                        pr_warning("Out of memory: discarding thread stack\n");
 197                        ts->cnt = 0;
 198                }
 199        }
 200
 201        ts->stack[ts->cnt].trace_end = trace_end;
 202        ts->stack[ts->cnt++].ret_addr = ret_addr;
 203
 204        return err;
 205}
 206
 207static void thread_stack__pop(struct thread_stack *ts, u64 ret_addr)
 208{
 209        size_t i;
 210
 211        /*
 212         * In some cases there may be functions which are not seen to return.
 213         * For example when setjmp / longjmp has been used.  Or the perf context
 214         * switch in the kernel which doesn't stop and start tracing in exactly
 215         * the same code path.  When that happens the return address will be
 216         * further down the stack.  If the return address is not found at all,
 217         * we assume the opposite (i.e. this is a return for a call that wasn't
 218         * seen for some reason) and leave the stack alone.
 219         */
 220        for (i = ts->cnt; i; ) {
 221                if (ts->stack[--i].ret_addr == ret_addr) {
 222                        ts->cnt = i;
 223                        return;
 224                }
 225        }
 226}
 227
 228static void thread_stack__pop_trace_end(struct thread_stack *ts)
 229{
 230        size_t i;
 231
 232        for (i = ts->cnt; i; ) {
 233                if (ts->stack[--i].trace_end)
 234                        ts->cnt = i;
 235                else
 236                        return;
 237        }
 238}
 239
 240static bool thread_stack__in_kernel(struct thread_stack *ts)
 241{
 242        if (!ts->cnt)
 243                return false;
 244
 245        return ts->stack[ts->cnt - 1].cp->in_kernel;
 246}
 247
 248static int thread_stack__call_return(struct thread *thread,
 249                                     struct thread_stack *ts, size_t idx,
 250                                     u64 timestamp, u64 ref, bool no_return)
 251{
 252        struct call_return_processor *crp = ts->crp;
 253        struct thread_stack_entry *tse;
 254        struct call_return cr = {
 255                .thread = thread,
 256                .comm = ts->comm,
 257                .db_id = 0,
 258        };
 259
 260        tse = &ts->stack[idx];
 261        cr.cp = tse->cp;
 262        cr.call_time = tse->timestamp;
 263        cr.return_time = timestamp;
 264        cr.branch_count = ts->branch_count - tse->branch_count;
 265        cr.call_ref = tse->ref;
 266        cr.return_ref = ref;
 267        if (tse->no_call)
 268                cr.flags |= CALL_RETURN_NO_CALL;
 269        if (no_return)
 270                cr.flags |= CALL_RETURN_NO_RETURN;
 271
 272        return crp->process(&cr, crp->data);
 273}
 274
 275static int __thread_stack__flush(struct thread *thread, struct thread_stack *ts)
 276{
 277        struct call_return_processor *crp = ts->crp;
 278        int err;
 279
 280        if (!crp) {
 281                ts->cnt = 0;
 282                return 0;
 283        }
 284
 285        while (ts->cnt) {
 286                err = thread_stack__call_return(thread, ts, --ts->cnt,
 287                                                ts->last_time, 0, true);
 288                if (err) {
 289                        pr_err("Error flushing thread stack!\n");
 290                        ts->cnt = 0;
 291                        return err;
 292                }
 293        }
 294
 295        return 0;
 296}
 297
 298int thread_stack__flush(struct thread *thread)
 299{
 300        struct thread_stack *ts = thread->ts;
 301        unsigned int pos;
 302        int err = 0;
 303
 304        if (ts) {
 305                for (pos = 0; pos < ts->arr_sz; pos++) {
 306                        int ret = __thread_stack__flush(thread, ts + pos);
 307
 308                        if (ret)
 309                                err = ret;
 310                }
 311        }
 312
 313        return err;
 314}
 315
 316int thread_stack__event(struct thread *thread, int cpu, u32 flags, u64 from_ip,
 317                        u64 to_ip, u16 insn_len, u64 trace_nr)
 318{
 319        struct thread_stack *ts = thread__stack(thread, cpu);
 320
 321        if (!thread)
 322                return -EINVAL;
 323
 324        if (!ts) {
 325                ts = thread_stack__new(thread, cpu, NULL);
 326                if (!ts) {
 327                        pr_warning("Out of memory: no thread stack\n");
 328                        return -ENOMEM;
 329                }
 330                ts->trace_nr = trace_nr;
 331        }
 332
 333        /*
 334         * When the trace is discontinuous, the trace_nr changes.  In that case
 335         * the stack might be completely invalid.  Better to report nothing than
 336         * to report something misleading, so flush the stack.
 337         */
 338        if (trace_nr != ts->trace_nr) {
 339                if (ts->trace_nr)
 340                        __thread_stack__flush(thread, ts);
 341                ts->trace_nr = trace_nr;
 342        }
 343
 344        /* Stop here if thread_stack__process() is in use */
 345        if (ts->crp)
 346                return 0;
 347
 348        if (flags & PERF_IP_FLAG_CALL) {
 349                u64 ret_addr;
 350
 351                if (!to_ip)
 352                        return 0;
 353                ret_addr = from_ip + insn_len;
 354                if (ret_addr == to_ip)
 355                        return 0; /* Zero-length calls are excluded */
 356                return thread_stack__push(ts, ret_addr,
 357                                          flags & PERF_IP_FLAG_TRACE_END);
 358        } else if (flags & PERF_IP_FLAG_TRACE_BEGIN) {
 359                /*
 360                 * If the caller did not change the trace number (which would
 361                 * have flushed the stack) then try to make sense of the stack.
 362                 * Possibly, tracing began after returning to the current
 363                 * address, so try to pop that. Also, do not expect a call made
 364                 * when the trace ended, to return, so pop that.
 365                 */
 366                thread_stack__pop(ts, to_ip);
 367                thread_stack__pop_trace_end(ts);
 368        } else if ((flags & PERF_IP_FLAG_RETURN) && from_ip) {
 369                thread_stack__pop(ts, to_ip);
 370        }
 371
 372        return 0;
 373}
 374
 375void thread_stack__set_trace_nr(struct thread *thread, int cpu, u64 trace_nr)
 376{
 377        struct thread_stack *ts = thread__stack(thread, cpu);
 378
 379        if (!ts)
 380                return;
 381
 382        if (trace_nr != ts->trace_nr) {
 383                if (ts->trace_nr)
 384                        __thread_stack__flush(thread, ts);
 385                ts->trace_nr = trace_nr;
 386        }
 387}
 388
 389static void __thread_stack__free(struct thread *thread, struct thread_stack *ts)
 390{
 391        __thread_stack__flush(thread, ts);
 392        zfree(&ts->stack);
 393}
 394
 395static void thread_stack__reset(struct thread *thread, struct thread_stack *ts)
 396{
 397        unsigned int arr_sz = ts->arr_sz;
 398
 399        __thread_stack__free(thread, ts);
 400        memset(ts, 0, sizeof(*ts));
 401        ts->arr_sz = arr_sz;
 402}
 403
 404void thread_stack__free(struct thread *thread)
 405{
 406        struct thread_stack *ts = thread->ts;
 407        unsigned int pos;
 408
 409        if (ts) {
 410                for (pos = 0; pos < ts->arr_sz; pos++)
 411                        __thread_stack__free(thread, ts + pos);
 412                zfree(&thread->ts);
 413        }
 414}
 415
 416static inline u64 callchain_context(u64 ip, u64 kernel_start)
 417{
 418        return ip < kernel_start ? PERF_CONTEXT_USER : PERF_CONTEXT_KERNEL;
 419}
 420
 421void thread_stack__sample(struct thread *thread, int cpu,
 422                          struct ip_callchain *chain,
 423                          size_t sz, u64 ip, u64 kernel_start)
 424{
 425        struct thread_stack *ts = thread__stack(thread, cpu);
 426        u64 context = callchain_context(ip, kernel_start);
 427        u64 last_context;
 428        size_t i, j;
 429
 430        if (sz < 2) {
 431                chain->nr = 0;
 432                return;
 433        }
 434
 435        chain->ips[0] = context;
 436        chain->ips[1] = ip;
 437
 438        if (!ts) {
 439                chain->nr = 2;
 440                return;
 441        }
 442
 443        last_context = context;
 444
 445        for (i = 2, j = 1; i < sz && j <= ts->cnt; i++, j++) {
 446                ip = ts->stack[ts->cnt - j].ret_addr;
 447                context = callchain_context(ip, kernel_start);
 448                if (context != last_context) {
 449                        if (i >= sz - 1)
 450                                break;
 451                        chain->ips[i++] = context;
 452                        last_context = context;
 453                }
 454                chain->ips[i] = ip;
 455        }
 456
 457        chain->nr = i;
 458}
 459
 460struct call_return_processor *
 461call_return_processor__new(int (*process)(struct call_return *cr, void *data),
 462                           void *data)
 463{
 464        struct call_return_processor *crp;
 465
 466        crp = zalloc(sizeof(struct call_return_processor));
 467        if (!crp)
 468                return NULL;
 469        crp->cpr = call_path_root__new();
 470        if (!crp->cpr)
 471                goto out_free;
 472        crp->process = process;
 473        crp->data = data;
 474        return crp;
 475
 476out_free:
 477        free(crp);
 478        return NULL;
 479}
 480
 481void call_return_processor__free(struct call_return_processor *crp)
 482{
 483        if (crp) {
 484                call_path_root__free(crp->cpr);
 485                free(crp);
 486        }
 487}
 488
 489static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr,
 490                                 u64 timestamp, u64 ref, struct call_path *cp,
 491                                 bool no_call, bool trace_end)
 492{
 493        struct thread_stack_entry *tse;
 494        int err;
 495
 496        if (ts->cnt == ts->sz) {
 497                err = thread_stack__grow(ts);
 498                if (err)
 499                        return err;
 500        }
 501
 502        tse = &ts->stack[ts->cnt++];
 503        tse->ret_addr = ret_addr;
 504        tse->timestamp = timestamp;
 505        tse->ref = ref;
 506        tse->branch_count = ts->branch_count;
 507        tse->cp = cp;
 508        tse->no_call = no_call;
 509        tse->trace_end = trace_end;
 510
 511        return 0;
 512}
 513
 514static int thread_stack__pop_cp(struct thread *thread, struct thread_stack *ts,
 515                                u64 ret_addr, u64 timestamp, u64 ref,
 516                                struct symbol *sym)
 517{
 518        int err;
 519
 520        if (!ts->cnt)
 521                return 1;
 522
 523        if (ts->cnt == 1) {
 524                struct thread_stack_entry *tse = &ts->stack[0];
 525
 526                if (tse->cp->sym == sym)
 527                        return thread_stack__call_return(thread, ts, --ts->cnt,
 528                                                         timestamp, ref, false);
 529        }
 530
 531        if (ts->stack[ts->cnt - 1].ret_addr == ret_addr) {
 532                return thread_stack__call_return(thread, ts, --ts->cnt,
 533                                                 timestamp, ref, false);
 534        } else {
 535                size_t i = ts->cnt - 1;
 536
 537                while (i--) {
 538                        if (ts->stack[i].ret_addr != ret_addr)
 539                                continue;
 540                        i += 1;
 541                        while (ts->cnt > i) {
 542                                err = thread_stack__call_return(thread, ts,
 543                                                                --ts->cnt,
 544                                                                timestamp, ref,
 545                                                                true);
 546                                if (err)
 547                                        return err;
 548                        }
 549                        return thread_stack__call_return(thread, ts, --ts->cnt,
 550                                                         timestamp, ref, false);
 551                }
 552        }
 553
 554        return 1;
 555}
 556
 557static int thread_stack__bottom(struct thread_stack *ts,
 558                                struct perf_sample *sample,
 559                                struct addr_location *from_al,
 560                                struct addr_location *to_al, u64 ref)
 561{
 562        struct call_path_root *cpr = ts->crp->cpr;
 563        struct call_path *cp;
 564        struct symbol *sym;
 565        u64 ip;
 566
 567        if (sample->ip) {
 568                ip = sample->ip;
 569                sym = from_al->sym;
 570        } else if (sample->addr) {
 571                ip = sample->addr;
 572                sym = to_al->sym;
 573        } else {
 574                return 0;
 575        }
 576
 577        cp = call_path__findnew(cpr, &cpr->call_path, sym, ip,
 578                                ts->kernel_start);
 579        if (!cp)
 580                return -ENOMEM;
 581
 582        return thread_stack__push_cp(ts, ip, sample->time, ref, cp,
 583                                     true, false);
 584}
 585
 586static int thread_stack__no_call_return(struct thread *thread,
 587                                        struct thread_stack *ts,
 588                                        struct perf_sample *sample,
 589                                        struct addr_location *from_al,
 590                                        struct addr_location *to_al, u64 ref)
 591{
 592        struct call_path_root *cpr = ts->crp->cpr;
 593        struct call_path *cp, *parent;
 594        u64 ks = ts->kernel_start;
 595        int err;
 596
 597        if (sample->ip >= ks && sample->addr < ks) {
 598                /* Return to userspace, so pop all kernel addresses */
 599                while (thread_stack__in_kernel(ts)) {
 600                        err = thread_stack__call_return(thread, ts, --ts->cnt,
 601                                                        sample->time, ref,
 602                                                        true);
 603                        if (err)
 604                                return err;
 605                }
 606
 607                /* If the stack is empty, push the userspace address */
 608                if (!ts->cnt) {
 609                        cp = call_path__findnew(cpr, &cpr->call_path,
 610                                                to_al->sym, sample->addr,
 611                                                ts->kernel_start);
 612                        if (!cp)
 613                                return -ENOMEM;
 614                        return thread_stack__push_cp(ts, 0, sample->time, ref,
 615                                                     cp, true, false);
 616                }
 617        } else if (thread_stack__in_kernel(ts) && sample->ip < ks) {
 618                /* Return to userspace, so pop all kernel addresses */
 619                while (thread_stack__in_kernel(ts)) {
 620                        err = thread_stack__call_return(thread, ts, --ts->cnt,
 621                                                        sample->time, ref,
 622                                                        true);
 623                        if (err)
 624                                return err;
 625                }
 626        }
 627
 628        if (ts->cnt)
 629                parent = ts->stack[ts->cnt - 1].cp;
 630        else
 631                parent = &cpr->call_path;
 632
 633        /* This 'return' had no 'call', so push and pop top of stack */
 634        cp = call_path__findnew(cpr, parent, from_al->sym, sample->ip,
 635                                ts->kernel_start);
 636        if (!cp)
 637                return -ENOMEM;
 638
 639        err = thread_stack__push_cp(ts, sample->addr, sample->time, ref, cp,
 640                                    true, false);
 641        if (err)
 642                return err;
 643
 644        return thread_stack__pop_cp(thread, ts, sample->addr, sample->time, ref,
 645                                    to_al->sym);
 646}
 647
 648static int thread_stack__trace_begin(struct thread *thread,
 649                                     struct thread_stack *ts, u64 timestamp,
 650                                     u64 ref)
 651{
 652        struct thread_stack_entry *tse;
 653        int err;
 654
 655        if (!ts->cnt)
 656                return 0;
 657
 658        /* Pop trace end */
 659        tse = &ts->stack[ts->cnt - 1];
 660        if (tse->trace_end) {
 661                err = thread_stack__call_return(thread, ts, --ts->cnt,
 662                                                timestamp, ref, false);
 663                if (err)
 664                        return err;
 665        }
 666
 667        return 0;
 668}
 669
 670static int thread_stack__trace_end(struct thread_stack *ts,
 671                                   struct perf_sample *sample, u64 ref)
 672{
 673        struct call_path_root *cpr = ts->crp->cpr;
 674        struct call_path *cp;
 675        u64 ret_addr;
 676
 677        /* No point having 'trace end' on the bottom of the stack */
 678        if (!ts->cnt || (ts->cnt == 1 && ts->stack[0].ref == ref))
 679                return 0;
 680
 681        cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp, NULL, 0,
 682                                ts->kernel_start);
 683        if (!cp)
 684                return -ENOMEM;
 685
 686        ret_addr = sample->ip + sample->insn_len;
 687
 688        return thread_stack__push_cp(ts, ret_addr, sample->time, ref, cp,
 689                                     false, true);
 690}
 691
 692int thread_stack__process(struct thread *thread, struct comm *comm,
 693                          struct perf_sample *sample,
 694                          struct addr_location *from_al,
 695                          struct addr_location *to_al, u64 ref,
 696                          struct call_return_processor *crp)
 697{
 698        struct thread_stack *ts = thread__stack(thread, sample->cpu);
 699        int err = 0;
 700
 701        if (ts && !ts->crp) {
 702                /* Supersede thread_stack__event() */
 703                thread_stack__reset(thread, ts);
 704                ts = NULL;
 705        }
 706
 707        if (!ts) {
 708                ts = thread_stack__new(thread, sample->cpu, crp);
 709                if (!ts)
 710                        return -ENOMEM;
 711                ts->comm = comm;
 712        }
 713
 714        /* Flush stack on exec */
 715        if (ts->comm != comm && thread->pid_ == thread->tid) {
 716                err = __thread_stack__flush(thread, ts);
 717                if (err)
 718                        return err;
 719                ts->comm = comm;
 720        }
 721
 722        /* If the stack is empty, put the current symbol on the stack */
 723        if (!ts->cnt) {
 724                err = thread_stack__bottom(ts, sample, from_al, to_al, ref);
 725                if (err)
 726                        return err;
 727        }
 728
 729        ts->branch_count += 1;
 730        ts->last_time = sample->time;
 731
 732        if (sample->flags & PERF_IP_FLAG_CALL) {
 733                bool trace_end = sample->flags & PERF_IP_FLAG_TRACE_END;
 734                struct call_path_root *cpr = ts->crp->cpr;
 735                struct call_path *cp;
 736                u64 ret_addr;
 737
 738                if (!sample->ip || !sample->addr)
 739                        return 0;
 740
 741                ret_addr = sample->ip + sample->insn_len;
 742                if (ret_addr == sample->addr)
 743                        return 0; /* Zero-length calls are excluded */
 744
 745                cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp,
 746                                        to_al->sym, sample->addr,
 747                                        ts->kernel_start);
 748                if (!cp)
 749                        return -ENOMEM;
 750                err = thread_stack__push_cp(ts, ret_addr, sample->time, ref,
 751                                            cp, false, trace_end);
 752        } else if (sample->flags & PERF_IP_FLAG_RETURN) {
 753                if (!sample->ip || !sample->addr)
 754                        return 0;
 755
 756                err = thread_stack__pop_cp(thread, ts, sample->addr,
 757                                           sample->time, ref, from_al->sym);
 758                if (err) {
 759                        if (err < 0)
 760                                return err;
 761                        err = thread_stack__no_call_return(thread, ts, sample,
 762                                                           from_al, to_al, ref);
 763                }
 764        } else if (sample->flags & PERF_IP_FLAG_TRACE_BEGIN) {
 765                err = thread_stack__trace_begin(thread, ts, sample->time, ref);
 766        } else if (sample->flags & PERF_IP_FLAG_TRACE_END) {
 767                err = thread_stack__trace_end(ts, sample, ref);
 768        }
 769
 770        return err;
 771}
 772
 773size_t thread_stack__depth(struct thread *thread, int cpu)
 774{
 775        struct thread_stack *ts = thread__stack(thread, cpu);
 776
 777        if (!ts)
 778                return 0;
 779        return ts->cnt;
 780}
 781