Example #1
0
/*!
 * \brief TClassContainer constructor.
 * \param base      [in] Parent class container instance.
 * \param needToClr [in] Flag of deallocate all data on destructor.
 */
TClassContainer::TClassContainer(TClassContainer *base, bool needToClr)
    : localContainers() {
  /* Initialize each field. */
  lockval = 0;
  queueLock = 0;
  needToClear = needToClr;
  classMap = NULL;
  pSender = NULL;
  unloadedList = NULL;

  if (likely(base != NULL)) {
    /* Get parent container's spin lock. */
    spinLockWait(&base->lockval);
  }

  try {
    if (unlikely(base == NULL)) {
      classMap = new TClassMap();
    } else {
      classMap = new TClassMap(*base->classMap);
    }
  } catch (...) {
    /*
     * This statement is for release lock. So allocate check is after.
     */
  }

  if (likely(base != NULL)) {
    /* Release parent container's spin lock. */
    spinLockRelease(&base->lockval);
  }

  try {
    /* Check classMap. */
    if (unlikely(classMap == NULL)) {
      throw 1;
    }

    /* Create trap sender. */
    if (conf->SnmpSend()->get()) {
      pSender = new TTrapSender(SNMP_VERSION_2c, conf->SnmpTarget()->get(),
                                conf->SnmpComName()->get(), 162);
    } else {
      pSender = NULL;
    }

    /* Create unloaded class information queue. */
    unloadedList = new TClassInfoQueue();

    /* Create thread storage key. */
    if (unlikely(pthread_key_create(&clsContainerKey, NULL) != 0)) {
      throw 1;
    }
  } catch (...) {
    delete classMap;
    delete pSender;
    delete unloadedList;
    throw "TClassContainer initialize failed!";
  }
}
Example #2
0
/*!
 * \brief Remove all-class from container.
 */
void TClassContainer::allClear(void) {
  /* Get spin lock of containers queue. */
  spinLockWait(&queueLock);
  {
    /* Broadcast to each local container. */
    for (TLocalClassContainer::iterator it = localContainers.begin();
         it != localContainers.end(); it++) {
      /* Get local container's spin lock. */
      spinLockWait(&(*it)->lockval);
      { (*it)->classMap->clear(); }
      /* Release local container's spin lock. */
      spinLockRelease(&(*it)->lockval);
    }
  }
  /* Release spin lock of containers queue. */
  spinLockRelease(&queueLock);

  /* Get class container's spin lock. */
  spinLockWait(&lockval);
  {
    /* Free allocated memory at class map. */
    for (TClassMap::iterator cur = classMap->begin(); cur != classMap->end();
         ++cur) {
      TObjectData *pos = (*cur).second;

      if (likely(pos != NULL)) {
        free(pos->className);
        free(pos);
      }
    }

    /* Free allocated memory at unloaded list. */
    while (!unloadedList->empty()) {
      TObjectData *pos = unloadedList->front();
      unloadedList->pop();

      free(pos->className);
      free(pos);
    }

    /* Clear all class. */
    classMap->clear();
  }
  /* Release class container's spin lock. */
  spinLockRelease(&lockval);
}
Example #3
0
  /*!
   * \brief Get class entries count.
   * \return Entries count of class information.
   */
  inline size_t getContainerSize(void) {
    size_t result = 0;

    /* Get class container's spin lock. */
    spinLockWait(&lockval);
    { result = this->classMap->size(); }
    /* Release class container's spin lock. */
    spinLockRelease(&lockval);
    return result;
  }
Example #4
0
/*!
 * \brief Remove class from container.
 * \param target [in] Remove class data.
 */
void TClassContainer::removeClass(TObjectData *target) {
  /* Remove item from map. Please callee has container's lock. */
  classMap->erase(target->klassOop);

  /* Get spin lock of containers queue. */
  spinLockWait(&queueLock);
  {
    /* Broadcast to each local container. */
    for (TLocalClassContainer::iterator it = localContainers.begin();
         it != localContainers.end(); it++) {
      /* Get local container's spin lock. */
      spinLockWait(&(*it)->lockval);
      { (*it)->classMap->erase(target->klassOop); }
      /* Release local container's spin lock. */
      spinLockRelease(&(*it)->lockval);
    }
  }
  /* Release spin lock of containers queue. */
  spinLockRelease(&queueLock);
}
Example #5
0
  /*!
   * \brief Update class oop.
   * \param oldKlassOop [in] Target old class oop.
   * \param newKlassOop [in] Target new class oop.
   * \return Class data of target class.
   */
  inline void updateClass(void *oldKlassOop, void *newKlassOop) {
    /* Get class container's spin lock. */
    spinLockWait(&lockval);
    {
      /* Search class data. */
      TClassMap::iterator it = classMap->find(oldKlassOop);
      if (it != classMap->end()) {
        TObjectData *cur = (*it).second;

        /* Remove old klassOop. */
        classMap->erase(it);

        try {
          /* Update class data. */
          (*classMap)[newKlassOop] = cur;
          cur->klassOop = newKlassOop;
        } catch (...) {
          /*
           * Maybe failed to allocate memory
           * at "std::map::operator[]".
           */
        }
      }
    }
    /* Release class container's spin lock. */
    spinLockRelease(&lockval);

    /* Get spin lock of containers queue. */
    spinLockWait(&queueLock);
    {
      TLocalClassContainer::iterator it = localContainers.begin();
      /* Broadcast to each local container. */
      for (; it != localContainers.end(); it++) {
        (*it)->updateClass(oldKlassOop, newKlassOop);
      }
    }
    /* Release spin lock of containers queue. */
    spinLockRelease(&queueLock);
  }
Example #6
0
/*!
 * \brief Enqueue new event.
 *
 * \param thread [in] jthread object which occurs new event.
 * \param event [in] New thread event.
 * \param additionalData [in] Additional data if exist.
 */
void TThreadRecorder::putEvent(jthread thread, TThreadEvent event,
                               jlong additionalData) {
    struct timeval tv;
    gettimeofday(&tv, NULL);

    TEventRecord eventRecord __attribute__((aligned(32))); // for YMM vmovdqa

    eventRecord.time = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
    eventRecord.thread_id =
        TVMFunctions::getInstance()->GetThreadId(*(void **)thread);
    eventRecord.event = event;
    eventRecord.additionalData = additionalData;

    if (unlikely(top_of_buffer->event == ThreadEnd)) {
        spinLockWait(&idmapLockVal);
        {
            std::tr1::unordered_map<jlong, char *, TNumericalHasher<jlong> >
            ::iterator entry = threadIDMap.find(top_of_buffer->thread_id);

            if (likely(entry != threadIDMap.end())) {
                free(entry->second);
                threadIDMap.erase(entry);
            }
        }
        spinLockRelease(&idmapLockVal);
    }

    spinLockWait(&bufferLockVal);
    {
        memcpy32(top_of_buffer, &eventRecord);

        if (unlikely(++top_of_buffer == end_of_buffer)) {
            top_of_buffer = (TEventRecord *)record_buffer;
        }
    }
    spinLockRelease(&bufferLockVal);
}
Example #7
0
  /*!
   * \brief Search class from container.
   * \param klassOop [in] Target class oop.
   * \return Class data of target class.
   */
  inline TObjectData *findClass(void *klassOop) {
    /* Search class data. */
    TObjectData *result = NULL;

    /* Get class container's spin lock. */
    spinLockWait(&lockval);
    {
      /* Search class data. */
      TClassMap::iterator it = classMap->find(klassOop);
      if (it != classMap->end()) {
        result = (*it).second;
      }
    }
    /* Release class container's spin lock. */
    spinLockRelease(&lockval);

    return result;
  }
Example #8
0
/*!
 * \brief Register new thread to thread id map.
 *
 * \param jvmti [in] JVMTI environment.
 * \param thread [in] jthread object of new thread.
 */
void TThreadRecorder::registerNewThread(jvmtiEnv *jvmti, jthread thread) {
    void *thread_oop = *(void **)thread;
    jlong id = TVMFunctions::getInstance()->GetThreadId(thread_oop);

    jvmtiThreadInfo threadInfo;
    jvmti->GetThreadInfo(thread, &threadInfo);

    spinLockWait(&idmapLockVal);
    {
        char *current_val = threadIDMap[id];

        if (unlikely(current_val != NULL)) {
            free(current_val);
        }

        threadIDMap[id] = strdup(threadInfo.name);
    }
    spinLockRelease(&idmapLockVal);

    jvmti->Deallocate((unsigned char *)threadInfo.name);
}
Example #9
0
  /*!
   * \brief Get local class container with each threads.
   * \return Local class container instance for this thread.
   */
  inline TClassContainer *getLocalContainer(void) {
    /* Get container for this thread. */
    TClassContainer *result =
        (TClassContainer *)pthread_getspecific(clsContainerKey);

    /* If container isn't exists yet. */
    if (unlikely(result == NULL)) {
      try {
        result = new TClassContainer(this, false);
      } catch (...) {
        /* Maybe raised badalloc exception. */
        return NULL;
      }
      pthread_setspecific(clsContainerKey, result);

      bool isFailure = false;
      /* Get spin lock of containers queue. */
      spinLockWait(&queueLock);
      {
        try {
          localContainers.push_back(result);
        } catch (...) {
          /* Maybe failed to add queue. */
          isFailure = true;
        }
      }
      /* Release spin lock of containers queue. */
      spinLockRelease(&queueLock);

      if (unlikely(isFailure)) {
        delete result;
        result = NULL;
      }
    }

    return result;
  }
Example #10
0
/*!
 * \brief Dump record data to file.
 *
 * \param fname [in] File name to dump record data.
 */
void TThreadRecorder::dump(const char *fname) {
    int fd = creat(fname, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

    if (fd == -1) {
        logger->printWarnMsgWithErrno("Thread Recorder dump failed.");
        throw errno;
    }

    /* Write byte order mark. */
    char bom = BOM;
    write(fd, &bom, sizeof(char));

    spinLockWait(&idmapLockVal);
    {
        /* Dump thread list. */
        int threadIDMapSize = threadIDMap.size();
        write(fd, &threadIDMapSize, sizeof(int));

        for (std::tr1::unordered_map<jlong, char *,
                TNumericalHasher<jlong> >::iterator itr =
                    threadIDMap.begin();
                itr != threadIDMap.end(); itr++) {
            jlong id = itr->first;
            int classname_length = strlen(itr->second);
            write(fd, &id, sizeof(jlong));
            write(fd, &classname_length, sizeof(int));
            write(fd, itr->second, classname_length);
        }

        /* Dump thread event. */
        write(fd, record_buffer, aligned_buffer_size);
    }
    spinLockRelease(&idmapLockVal);

    close(fd);
}
Example #11
0
/*!
 * \brief Commit class information changing in class container.<br>
 *        This function is for avoiding trouble with class map.<br>
 *        At "afterTakeSnapShot", map is copied as shadow copy.<br>
 *        So crash JVM,
 *        if we remove item and output map at the same times.
 */
void TClassContainer::commitClassChange(void) {
  TClassInfoQueue *list = NULL;

  /* Get class container's spin lock. */
  spinLockWait(&lockval);
  {
    /* Remove unloaded class which detected at "pushNewClass". */
    while (!unloadedList->empty()) {
      TObjectData *target = unloadedList->front();
      unloadedList->pop();

      /* Free allocated memory. */
      free(target->className);
      free(target);
    }

    try {
      list = new TClassInfoQueue();

      /* Search delete target. */
      for (TClassMap::iterator cur = classMap->begin(); cur != classMap->end();
           ++cur) {
        TObjectData *objData = (*cur).second;

        /* If class is prepared remove from class container. */
        if (unlikely(objData->oldTotalSize == 0 && objData->isRemoved)) {
          /*
           * If we do removing map item here,
           * iterator's relationship will be broken.
           * So we store to list. And we remove after iterator loop.
           */
          list->push(objData);
        }
      }
    } catch (...) {
      /*
       * Maybe failed to allocate memory.
       * E.g. raise exception at "new", "std::queue<T>::push" or etc..
       */
      delete list;
      list = NULL;
    }

    if (likely(list != NULL)) {
      /* Remove delete target. */
      while (!list->empty()) {
        TObjectData *target = list->front();
        list->pop();

        /* Remove from all containers. */
        removeClass(target);

        /* Free allocated memory. */
        free(target->className);
        free(target);
      }
    }
  }
  /* Release class container's spin lock. */
  spinLockRelease(&lockval);

  /* Cleanup. */
  delete list;
}
Example #12
0
/*!
 * \brief Output all-class information to file.
 * \param snapshot [in]  Snapshot instance.
 * \param rank     [out] Sorted-class information.
 * \return Value is zero, if process is succeed.<br />
 *         Value is error number a.k.a. "errno", if process is failure.
 */
int TClassContainer::afterTakeSnapShot(TSnapShotContainer *snapshot,
                                       TSorter<THeapDelta> **rank) {
  /* Sanity check. */
  if (unlikely(snapshot == NULL || rank == NULL)) {
    return 0;
  }

  /* Copy header. */
  TSnapShotFileHeader hdr;
  memcpy(&hdr, (const void *)snapshot->getHeader(),
         sizeof(TSnapShotFileHeader));

  /* If java heap usage alert is enable. */
  if (conf->getHeapAlertThreshold() > 0) {
    jlong usage = hdr.newAreaSize + hdr.oldAreaSize;

    if (usage > conf->getHeapAlertThreshold()) {
      /* Raise alert. */
      logger->printWarnMsg(
          "ALERT: Java heap usage exceeded the threshold (%ld MB)",
          usage / 1024 / 1024);

      /* If need send trap. */
      if (conf->SnmpSend()->get()) {
        if (unlikely(!sendMemoryUsageAlertTrap(pSender, ALERT_JAVA_HEAP,
                                               hdr.snapShotTime, usage,
                                               jvmInfo->getMaxMemory()))) {
          logger->printWarnMsg("SNMP trap send failed!");
        }
      }
    }
  }

  /* If metaspace usage alert is enable. */
  if ((conf->MetaspaceThreshold()->get() > 0) &&
      ((conf->MetaspaceThreshold()->get() * 1024 * 1024) <
       hdr.metaspaceUsage)) {
    const char *label = jvmInfo->isAfterCR6964458() ? "Metaspace" : "PermGen";

    /* Raise alert. */
    logger->printWarnMsg("ALERT: %s usage exceeded the threshold (%ld MB)",
                         label, hdr.metaspaceUsage / 1024 / 1024);

    /* If need send trap. */
    if (conf->SnmpSend()->get()) {
      if (unlikely(!sendMemoryUsageAlertTrap(
                       pSender, ALERT_METASPACE, hdr.snapShotTime,
                       hdr.metaspaceUsage, hdr.metaspaceCapacity))) {
        logger->printWarnMsg("SNMP trap send failed!");
      }
    }
  }

  /* Class map used snapshot output. */
  TClassMap *workClsMap = NULL;
  /* Get class container's spin lock. */
  spinLockWait(&lockval);
  {
    try {
      workClsMap = new TClassMap(*this->classMap);
    } catch (...) {
      workClsMap = NULL;
    }
  }
  /* Release class container's spin lock. */
  spinLockRelease(&lockval);

  if (unlikely(workClsMap == NULL)) {
    int raisedErrNum = errno;
    logger->printWarnMsgWithErrno("Couldn't allocate working memory!");
    return raisedErrNum;
  }

  /* Allocate return array. */
  jlong rankCnt = workClsMap->size();
  rankCnt =
      (rankCnt < conf->RankLevel()->get()) ? rankCnt : conf->RankLevel()->get();

  /* Make controller to sort. */
  register TRankOrder order = conf->Order()->get();
  TSorter<THeapDelta> *sortArray;
  try {
    sortArray = new TSorter<THeapDelta>(
        rankCnt,
        (TComparator)((order == DELTA) ? &HeapDeltaCmp : &HeapUsageCmp));
  } catch (...) {
    int raisedErrNum = errno;
    logger->printWarnMsgWithErrno("Couldn't allocate working memory!");
    delete workClsMap;
    return raisedErrNum;
  }

  /* Open file and seek EOF. */

  int fd = open(conf->FileName()->get(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
  /* If failure open file. */
  if (unlikely(fd < 0)) {
    int raisedErrNum = errno;
    logger->printWarnMsgWithErrno("Could not open %s", conf->FileName()->get());
    delete sortArray;
    delete workClsMap;
    return raisedErrNum;
  }

  off_t oldFileOffset = -1;
  try {
    /* Move position to EOF. */
    oldFileOffset = lseek(fd, 0, SEEK_END);
    /* If failure seek. */
    if (unlikely(oldFileOffset < 0)) {
      throw 1;
    }

    /* Frist, Output each classes information. Secondly output header. */
    if (unlikely(lseek(fd, sizeof(TSnapShotFileHeader) - sizeof(char[80]) +
                               hdr.gcCauseLen,
                       SEEK_CUR) < 0)) {
      throw 1;
    }
  } catch (...) {
    int raisedErrNum = errno;
    logger->printWarnMsg("Could not write snapshot");
    close(fd);
    delete sortArray;
    delete workClsMap;
    return raisedErrNum;
  }

  /* Output class information. */

  THeapDelta result;
  jlong numEntries = 0L;
  int raiseErrorCode = 0;
  register jlong AlertThreshold = conf->getAlertThreshold();

  /* Loop each class. */
  for (TClassMap::iterator it = workClsMap->begin(); it != workClsMap->end();
       ++it) {
    TObjectData *objData = (*it).second;
    TClassCounter *cur = snapshot->findClass(objData);
    /* If don't registed class yet. */
    if (unlikely(cur == NULL)) {
      cur = snapshot->pushNewClass(objData);
      if (unlikely(cur == NULL)) {
        raiseErrorCode = errno;
        logger->printWarnMsgWithErrno("Couldn't allocate working memory!");
        delete sortArray;
        sortArray = NULL;
        break;
      }
    }

    /* Calculate uasge and delta size. */
    result.usage = cur->counter->total_size;
    result.delta = cur->counter->total_size - objData->oldTotalSize;
    result.tag = objData->tag;
    objData->oldTotalSize = result.usage;

    /* If do output class. */
    if (!conf->ReduceSnapShot()->get() || (result.usage > 0)) {
      /* Output class-information. */
      if (likely(raiseErrorCode == 0)) {
        raiseErrorCode = writeClassData(fd, objData, cur);
      }

      numEntries++;
    }

    /* Ranking sort. */
    sortArray->push(result);

    /* If alert is enable. */
    if (AlertThreshold > 0) {
      /* Variable for send trap. */
      int sendFlag = 0;

      /* If size is bigger more limit size. */
      if ((order == DELTA) && (AlertThreshold <= result.delta)) {
        /* Raise alert. */
        logger->printWarnMsg(
            "ALERT(DELTA): \"%s\" exceeded the threshold (%ld bytes)",
            objData->className, result.delta);
        /* Set need send trap flag. */
        sendFlag = 1;
      } else if ((order == USAGE) && (AlertThreshold <= result.usage)) {
        /* Raise alert. */
        logger->printWarnMsg(
            "ALERT(USAGE): \"%s\" exceeded the threshold (%ld bytes)",
            objData->className, result.usage);
        /* Set need send trap flag. */
        sendFlag = 1;
      }

      /* If need send trap. */
      if (conf->SnmpSend()->get() && sendFlag != 0) {
        if (unlikely(!sendHeapAlertTrap(pSender, result, objData->className,
                                        cur->counter->count))) {
          logger->printWarnMsg("Send SNMP trap failed!");
        }
      }
    }
  }
  delete workClsMap;

  /* Set output entry count. */
  hdr.size = numEntries;
  /* Stored error number to avoid overwriting by "truncate" and etc.. */
  int raisedErrNum = 0;
  try {
    /* If already failed in processing to write snapshot. */
    if (unlikely(raiseErrorCode != 0)) {
      errno = raiseErrorCode;
      raisedErrNum = raiseErrorCode;
      throw 1;
    }

    /* If fail seeking to header position. */
    if (unlikely(lseek(fd, oldFileOffset, SEEK_SET) < 0)) {
      raisedErrNum = errno;
      throw 2;
    }

    raisedErrNum = writeHeader(fd, hdr);
    /* If failed to write a snapshot header. */
    if (unlikely(raisedErrNum != 0)) {
      throw 3;
    }
  } catch (...) {
    ; /* Failed to write file. */
  }

  /* Clean up. */
  if (unlikely(close(fd) != 0 && raisedErrNum == 0)) {
    errno = raisedErrNum;
    logger->printWarnMsgWithErrno("Could not write snapshot");
  }

  /* If need rollback snapshot. */
  if (unlikely(raisedErrNum != 0)) {
    if (unlikely(truncate(conf->FileName()->get(), oldFileOffset) < 0)) {
      logger->printWarnMsgWithErrno("Could not rollback snapshot");
    }
  }

  /* Cleanup. */
  (*rank) = sortArray;
  return raisedErrNum;
}
Example #13
0
/*!
 * \brief Append new-class to container.
 * \param klassOop [in] New class oop.
 * \param objData  [in] Add new class data.
 * \return New-class data.<br />
 *         This value isn't equal param "objData",
 *         if already registered equivalence class.
 */
TObjectData *TClassContainer::pushNewClass(void *klassOop,
                                           TObjectData *objData) {
  TObjectData *existData = NULL;
  /* Get class container's spin lock. */
  spinLockWait(&lockval);
  {
    /*
     * Jvmti extension event "classUnload" is loose once in a while.
     * The event forget callback occasionally when class unloading.
     * So we need to check klassOop that was doubling.
     */

    /* Check klassOop doubling. */
    TClassMap::iterator it = classMap->find(klassOop);
    if (likely(it != classMap->end())) {
      /* Store data to return value as result. */
      TObjectData *expectData = (*it).second;
      if (likely(expectData != NULL)) {
        /* If adding class data is already exists. */
        if (unlikely(expectData->className != NULL &&
                     strcmp(objData->className, expectData->className) == 0 &&
                     objData->clsLoaderId == expectData->clsLoaderId)) {
          /* Return existing data on map. */
          existData = expectData;
        } else {
          /* klass oop is doubling for another class. */
          removeClass(expectData);
          try {
            unloadedList->push(expectData);
          } catch (...) {
            /*
             * We try to continue running without crash
             * even if failed to allocate memory.
             */
          }
        }
      }
    }

    if (likely(existData == NULL)) {
      try {
        /* Append class data. */
        (*classMap)[klassOop] = objData;
      } catch (...) {
        /*
         * Maybe failed to allocate memory at "std::map::operator[]".
         */
      }
    }
  }
  /* Release class container's spin lock. */
  spinLockRelease(&lockval);

  /* If already exist class data. */
  if (unlikely(existData != NULL)) {
    return existData;
  }

  /* Get spin lock of containers queue. */
  spinLockWait(&queueLock);
  {
    /* Broadcast to each local container. */
    for (TLocalClassContainer::iterator it = localContainers.begin();
         it != localContainers.end(); it++) {
      (*it)->pushNewClass(klassOop, objData);
    }
  }
  /* Release spin lock of containers queue. */
  spinLockRelease(&queueLock);
  return objData;
}