public SearchResult searchFor(String pattern, String threadName) {
    pattern = pattern.toLowerCase(Locale.US);

    Set<MethodInfo> methods = new HashSet<MethodInfo>();
    Set<Call> calls = new HashSet<Call>();

    Call topLevelCall = getThread(threadName).getTopLevelCall();
    if (topLevelCall == null) {
      // no matches
      return new SearchResult(methods, calls);
    }

    // Find all methods matching given pattern called on given thread
    for (MethodInfo method : getMethods().values()) {
      String fullName = method.getFullName().toLowerCase(Locale.US);
      if (fullName.contains(pattern)) { // method name matches
        if (method.getInclusiveTime(threadName, ClockType.GLOBAL)
            > 0) { // method was called in this thread
          methods.add(method);
        }
      }
    }

    // Find all invocations of the matched methods
    Iterator<Call> iterator = topLevelCall.getCallHierarchyIterator();
    while (iterator.hasNext()) {
      Call c = iterator.next();
      MethodInfo method = getMethod(c.getMethodId());
      if (methods.contains(method)) {
        calls.add(c);
      }
    }

    return new SearchResult(methods, calls);
  }
  /** Returns the duration of this call as a percentage of the duration of the top level call. */
  public double getDurationPercentage(
      Call call, String threadName, ClockType clockType, boolean inclusiveTime) {
    Call topCall = getThread(threadName).getTopLevelCall();
    if (topCall == null) {
      return 100.;
    }

    MethodInfo methodInfo = getMethod(call.getMethodId());
    MethodInfo topInfo = getMethod(topCall.getMethodId());

    TimeSelector selector = TimeSelector.create(clockType, inclusiveTime);
    long methodTime = selector.get(methodInfo, threadName);

    // always use inclusive time to obtain the top level's time when computing percentages
    selector = TimeSelector.create(clockType, true);
    long topLevelTime = selector.get(topInfo, threadName);

    return (double) methodTime / topLevelTime * 100;
  }