void Thrman::execDBINFO_SCANREQ()

in storage/ndb/src/kernel/blocks/thrman.cpp [3432:4202]


void Thrman::execDBINFO_SCANREQ(Signal *signal) {
  jamEntry();

  DbinfoScanReq req = *(DbinfoScanReq *)signal->theData;
  const Ndbinfo::ScanCursor *cursor =
      CAST_CONSTPTR(Ndbinfo::ScanCursor, DbinfoScan::getCursorPtr(&req));
  Ndbinfo::Ratelimit rl;

  switch (req.tableId) {
    case Ndbinfo::HWINFO_TABLEID: {
      if (instance() == m_main_thrman_instance) {
        struct ndb_hwinfo *info = Ndb_GetHWInfo(false);
        Ndbinfo::Row row(signal, req);
        row.write_uint32(getOwnNodeId());
        row.write_uint32(info->cpu_cnt_max);
        row.write_uint32(info->cpu_cnt);
        row.write_uint32(info->num_cpu_cores);
        row.write_uint32(info->num_cpu_sockets);
        row.write_uint64(info->hw_memory_size);
        row.write_string(info->cpu_model_name);
        ndbinfo_send_row(signal, req, row, rl);
      }
      break;
    }
    case Ndbinfo::CPUINFO_TABLEID: {
      if (m_is_cpuinfo_available) {
        struct ndb_hwinfo *info = Ndb_GetHWInfo(false);
        Uint32 pos = cursor->data[0];
        for (;;) {
          Ndbinfo::Row row(signal, req);
          row.write_uint32(getOwnNodeId());
          row.write_uint32(info->cpu_info[pos].cpu_no);
          row.write_uint32(info->cpu_info[pos].online);
          row.write_uint32(info->cpu_info[pos].core_id);
          row.write_uint32(info->cpu_info[pos].socket_id);
          ndbinfo_send_row(signal, req, row, rl);
          pos++;
          if (pos == info->cpu_cnt_max) {
            break;
          }
          if (rl.need_break(req)) {
            jam();
            ndbinfo_send_scan_break(signal, req, rl, pos);
            return;
          }
        }
      }
      break;
    }
    case Ndbinfo::CPUDATA_TABLEID: {
      if (m_is_cpudata_available) {
        struct ndb_hwinfo *info = Ndb_GetHWInfo(false);
        Uint32 cpu_no = cursor->data[0];
        for (;;) {
          CPURecordPtr cpuPtr;
          CPUMeasurementRecordPtr cpuMeasurePtr;
          cpuPtr.i = cpu_no;
          c_CPURecordPool.getPtr(cpuPtr);
          {
            LocalDLCFifoList<CPUMeasurementRecord_pool> list(
                c_CPUMeasurementRecordPool, cpuPtr.p->m_next_1sec_measure);
            list.first(cpuMeasurePtr);
          }
          if (cpuMeasurePtr.p->m_first_measure_done) {
            send_cpu_measurement_row(req, rl, signal, cpuMeasurePtr, cpu_no,
                                     info->cpu_data[cpu_no].online);
          }
          cpu_no++;
          if (cpu_no == info->cpu_cnt_max) {
            break;
          }
          if (rl.need_break(req)) {
            jam();
            ndbinfo_send_scan_break(signal, req, rl, cpu_no);
            return;
          }
        }
      }
      break;
    }
    case Ndbinfo::CPUDATA_50MS_TABLEID:
    case Ndbinfo::CPUDATA_1SEC_TABLEID:
    case Ndbinfo::CPUDATA_20SEC_TABLEID: {
      if (m_is_cpudata_available) {
        struct ndb_hwinfo *info = Ndb_GetHWInfo(false);
        Uint32 cpu_no = cursor->data[0];
        for (;;) {
          CPURecordPtr cpuPtr;
          CPUMeasurementRecordPtr cpuMeasurePtr;
          cpuPtr.i = cpu_no;
          c_CPURecordPool.getPtr(cpuPtr);
          if (req.tableId == Ndbinfo::CPUDATA_50MS_TABLEID) {
            LocalDLCFifoList<CPUMeasurementRecord_pool> list(
                c_CPUMeasurementRecordPool, cpuPtr.p->m_next_50ms_measure);
            list.first(cpuMeasurePtr);
          } else if (req.tableId == Ndbinfo::CPUDATA_1SEC_TABLEID) {
            LocalDLCFifoList<CPUMeasurementRecord_pool> list(
                c_CPUMeasurementRecordPool, cpuPtr.p->m_next_1sec_measure);
            list.first(cpuMeasurePtr);
          } else if (req.tableId == Ndbinfo::CPUDATA_20SEC_TABLEID) {
            LocalDLCFifoList<CPUMeasurementRecord_pool> list(
                c_CPUMeasurementRecordPool, cpuPtr.p->m_next_20sec_measure);
            list.first(cpuMeasurePtr);
          } else {
            ndbabort();
          }
          Uint32 loop_count = 0;
          do {
            ndbrequire(loop_count < NUM_MEASUREMENTS);
            if (cpuMeasurePtr.p->m_first_measure_done) {
              send_cpu_raw_measurement_row(req, rl, signal, cpuMeasurePtr,
                                           cpu_no, loop_count,
                                           info->cpu_data[cpu_no].online);
            }
            if (req.tableId == Ndbinfo::CPUDATA_50MS_TABLEID) {
              LocalDLCFifoList<CPUMeasurementRecord_pool> list(
                  c_CPUMeasurementRecordPool, cpuPtr.p->m_next_50ms_measure);
              list.next(cpuMeasurePtr);
            } else if (req.tableId == Ndbinfo::CPUDATA_1SEC_TABLEID) {
              LocalDLCFifoList<CPUMeasurementRecord_pool> list(
                  c_CPUMeasurementRecordPool, cpuPtr.p->m_next_1sec_measure);
              list.next(cpuMeasurePtr);
            } else if (req.tableId == Ndbinfo::CPUDATA_20SEC_TABLEID) {
              LocalDLCFifoList<CPUMeasurementRecord_pool> list(
                  c_CPUMeasurementRecordPool, cpuPtr.p->m_next_20sec_measure);
              list.next(cpuMeasurePtr);
            } else {
              ndbabort();
            }
            loop_count++;
          } while (cpuMeasurePtr.i != RNIL);
          cpu_no++;
          if (cpu_no == info->cpu_cnt_max) {
            break;
          }
          if (rl.need_break(req)) {
            jam();
            ndbinfo_send_scan_break(signal, req, rl, cpu_no);
            return;
          }
        }
      }
      break;
    }
    case Ndbinfo::THREADS_TABLEID: {
      Uint32 pos = cursor->data[0];
      for (;;) {
        if (pos == 0) {
          jam();
          Ndbinfo::Row row(signal, req);
          row.write_uint32(getOwnNodeId());
          row.write_uint32(getThreadId());  // thr_no
          row.write_string(m_thread_name);
          row.write_string(m_thread_description);
          ndbinfo_send_row(signal, req, row, rl);
        }
        if (instance() != m_main_thrman_instance) {
          jam();
          break;
        }
        pos++;
        if (pos > m_num_send_threads) {
          jam();
          break;
        }
        {
          jam();
          Ndbinfo::Row row(signal, req);
          row.write_uint32(getOwnNodeId());
          row.write_uint32(m_num_threads + (pos - 1));  // thr_no
          row.write_string(m_send_thread_name);
          row.write_string(m_send_thread_description);
          ndbinfo_send_row(signal, req, row, rl);
        }

        if (pos >= m_num_send_threads) {
          jam();
          break;
        }

        if (rl.need_break(req)) {
          jam();
          ndbinfo_send_scan_break(signal, req, rl, pos);
          return;
        }
      }
      break;
    }
    case Ndbinfo::THREADBLOCKS_TABLEID: {
      Uint32 arr[MAX_INSTANCES_PER_THREAD];
      Uint32 len = mt_get_blocklist(this, arr, NDB_ARRAY_SIZE(arr));
      Uint32 pos = cursor->data[0];
      ndbrequire(pos < NDB_ARRAY_SIZE(arr));
      for (;;) {
        Ndbinfo::Row row(signal, req);
        row.write_uint32(getOwnNodeId());
        row.write_uint32(getThreadId());              // thr_no
        row.write_uint32(blockToMain(arr[pos]));      // block_number
        row.write_uint32(blockToInstance(arr[pos]));  // block_instance
        ndbinfo_send_row(signal, req, row, rl);

        pos++;
        if (pos == len) {
          jam();
          break;
        } else if (rl.need_break(req)) {
          jam();
          ndbinfo_send_scan_break(signal, req, rl, pos);
          return;
        }
      }
      break;
    }
    case Ndbinfo::THREADBLOCK_DETAILS_TABLEID: {
      Uint32 arr[MAX_INSTANCES_PER_THREAD];
      Uint32 len = mt_get_blocklist(this, arr, NDB_ARRAY_SIZE(arr));
      Uint32 pos = cursor->data[0];
      ndbrequire(pos < NDB_ARRAY_SIZE(arr));
      for (;;) {
        Ndbinfo::Row row(signal, req);
        row.write_uint32(getOwnNodeId());
        row.write_uint32(getThreadId());              // thr_no
        row.write_uint32(blockToMain(arr[pos]));      // block_number
        row.write_uint32(blockToInstance(arr[pos]));  // block_instance
#if defined(ERROR_INSERT)
        SimulatedBlock *block = globalData.getBlockInstance(arr[pos]);
        row.write_uint32(block->getErrorInsertValue());  // error_insert_value
        row.write_uint32(block->getErrorInsertExtra());  // error_insert_extra
#else
        row.write_null();  // error_insert_value
        row.write_null();  // error_insert_extra
#endif
        ndbinfo_send_row(signal, req, row, rl);

        pos++;
        if (pos == len) {
          jam();
          break;
        } else if (rl.need_break(req)) {
          jam();
          ndbinfo_send_scan_break(signal, req, rl, pos);
          return;
        }
      }
      break;
    }
    case Ndbinfo::THREADSTAT_TABLEID: {
      ndb_thr_stat stat;
      mt_get_thr_stat(this, &stat);
      Ndbinfo::Row row(signal, req);
      row.write_uint32(getOwnNodeId());
      row.write_uint32(getThreadId());  // thr_no
      row.write_string(stat.name);
      row.write_uint64(stat.loop_cnt);
      row.write_uint64(stat.exec_cnt);
      row.write_uint64(stat.wait_cnt);
      row.write_uint64(stat.local_sent_prioa);
      row.write_uint64(stat.local_sent_priob);
      row.write_uint64(stat.remote_sent_prioa);
      row.write_uint64(stat.remote_sent_priob);

      row.write_uint64(stat.os_tid);
      row.write_uint64(NdbTick_CurrentMillisecond());

      struct ndb_rusage os_rusage;
      Ndb_GetRUsage(&os_rusage, false);
      row.write_uint64(os_rusage.ru_utime);
      row.write_uint64(os_rusage.ru_stime);
      row.write_uint64(os_rusage.ru_minflt);
      row.write_uint64(os_rusage.ru_majflt);
      row.write_uint64(os_rusage.ru_nvcsw);
      row.write_uint64(os_rusage.ru_nivcsw);
      ndbinfo_send_row(signal, req, row, rl);
      break;
    }
    case Ndbinfo::CPUSTAT_50MS_TABLEID:
    case Ndbinfo::CPUSTAT_1SEC_TABLEID:
    case Ndbinfo::CPUSTAT_20SEC_TABLEID: {
      Uint32 pos = cursor->data[0];

      SendThreadMeasurementPtr sendThreadMeasurementPtr;
      MeasurementRecordPtr measurePtr;

      for (;;) {
        jam();
        Uint32 pos_thread_id = ((pos >> 8) & 255);
        Uint32 pos_index = (pos & 255);
        Uint32 pos_ptrI = (pos >> 16);
        sendThreadMeasurementPtr.i = RNIL;
        sendThreadMeasurementPtr.p = NULL;
        measurePtr.i = RNIL;
        measurePtr.p = NULL;
        if (pos_index >= NUM_MEASUREMENTS) {
          jam();
          ndbassert(false);
          g_eventLogger->info("pos_index out of range in ndbinfo table %u",
                              req.tableId);
          ndbinfo_send_scan_conf(signal, req, rl);
          return;
        }

        if (pos == 0) {
          /**
           * This is the first row to start. We start with the rows from our
           * own thread. The pos variable is divided in 3 fields.
           * Bit 0-7 contains index number from 0 up to 19.
           * Bit 8-15 contains thread number
           * Bit 16-31 is a pointer to the next SendThreadMeasurement record.
           *
           * Thread number 0 is our own thread always. Thread 1 is send thread
           * instance 0 and thread 2 send thread instance 1 and so forth. We
           * will only worry about send thread data in the main thread where
           * we keep track of this information.
           *
           * The latest measurement is at the end of the linked list and so we
           * proceed backwards in the list.
           */
          if (req.tableId == Ndbinfo::CPUSTAT_50MS_TABLEID) {
            jam();
            c_next_50ms_measure.last(measurePtr);
          } else if (req.tableId == Ndbinfo::CPUSTAT_1SEC_TABLEID) {
            jam();
            c_next_1sec_measure.last(measurePtr);
          } else if (req.tableId == Ndbinfo::CPUSTAT_20SEC_TABLEID) {
            jam();
            c_next_20sec_measure.last(measurePtr);
          } else {
            ndbabort();
            return;
          }
          /* Start at index 0, thread 0, measurePtr.i */
          pos = measurePtr.i << 16;
        } else if (pos_thread_id != 0) {
          /**
           * We are working on the send thread measurement as we are the
           * main thread.
           */
          jam();
          if (instance() != m_main_thrman_instance) {
            g_eventLogger->info("pos_thread_id = %u in non-main thread",
                                pos_thread_id);
            ndbassert(false);
            ndbinfo_send_scan_conf(signal, req, rl);
            return;
          }
          ndbrequire(c_sendThreadMeasurementPool.getPtr(
              sendThreadMeasurementPtr, pos_ptrI));
        } else {
          jam();
          ndbrequire(c_measurementRecordPool.getPtr(measurePtr, pos_ptrI));
        }

        Ndbinfo::Row row(signal, req);
        if (pos_thread_id == 0 && measurePtr.p->m_first_measure_done) {
          jam();
          /**
           * We report buffer_full_time, spin_time and exec_time as
           * separate times. So exec time does not include buffer_full_time
           * when we report it to the user and it also does not include
           * spin time when we report it to the user and finally it does
           * also not include send time of the thread. So essentially
           * the sum of exec_time, sleep_time, spin_time, send_time and
           * buffer_full_time should be very close to the elapsed time.
           */
          Uint32 exec_time = measurePtr.p->m_exec_time_thread;
          Uint32 spin_time = measurePtr.p->m_spin_time_thread;
          Uint32 buffer_full_time = measurePtr.p->m_buffer_full_time_thread;
          Uint32 send_time = measurePtr.p->m_send_time_thread;

          if (exec_time < (buffer_full_time + send_time + spin_time)) {
            exec_time = 0;
          } else {
            exec_time -= buffer_full_time;
            exec_time -= spin_time;
            exec_time -= send_time;
          }
          row.write_uint32(getOwnNodeId());
          row.write_uint32(getThreadId());
          row.write_uint32(Uint32(measurePtr.p->m_user_time_os));
          row.write_uint32(Uint32(measurePtr.p->m_kernel_time_os));
          row.write_uint32(Uint32(measurePtr.p->m_idle_time_os));
          row.write_uint32(Uint32(exec_time));
          row.write_uint32(Uint32(measurePtr.p->m_sleep_time_thread));
          row.write_uint32(Uint32(measurePtr.p->m_spin_time_thread));
          row.write_uint32(Uint32(measurePtr.p->m_send_time_thread));
          row.write_uint32(Uint32(measurePtr.p->m_buffer_full_time_thread));
          row.write_uint32(Uint32(measurePtr.p->m_elapsed_time));
          ndbinfo_send_row(signal, req, row, rl);
        } else if (pos_thread_id != 0 &&
                   sendThreadMeasurementPtr.p->m_first_measure_done) {
          jam();
          row.write_uint32(getOwnNodeId());
          row.write_uint32(m_num_threads + (pos_thread_id - 1));

          Uint32 exec_time = sendThreadMeasurementPtr.p->m_exec_time;
          Uint32 sleep_time = sendThreadMeasurementPtr.p->m_sleep_time;

          row.write_uint32(Uint32(sendThreadMeasurementPtr.p->m_user_time_os));
          row.write_uint32(
              Uint32(sendThreadMeasurementPtr.p->m_kernel_time_os));
          row.write_uint32(Uint32(sendThreadMeasurementPtr.p->m_idle_time_os));
          row.write_uint32(exec_time);
          row.write_uint32(sleep_time);
          row.write_uint32(0);
          row.write_uint32(exec_time);
          row.write_uint32(Uint32(0));
          Uint32 elapsed_time = sendThreadMeasurementPtr.p->m_exec_time +
                                sendThreadMeasurementPtr.p->m_sleep_time;
          row.write_uint32(elapsed_time);
          ndbinfo_send_row(signal, req, row, rl);
        } else {
          // Proceed to next thread at first undone measurement
          pos_index = NUM_MEASUREMENTS - 1;
        }

        if ((pos_index + 1) == NUM_MEASUREMENTS) {
          /**
           * We are done with this thread, we need to either move on to next
           * send thread or stop.
           */
          if (instance() != m_main_thrman_instance) {
            jam();
            break;
          }
          /* This check will also ensure that we break without send threads */
          if (pos_thread_id == m_num_send_threads) {
            jam();
            break;
          }
          jam();
          pos_thread_id++;
          SendThreadPtr sendThreadPtr;
          ndbrequire(
              c_sendThreadRecordPool.getPtr(sendThreadPtr, pos_thread_id - 1));

          if (req.tableId == Ndbinfo::CPUSTAT_50MS_TABLEID) {
            jam();
            Local_SendThreadMeasurement_fifo list_50ms(
                c_sendThreadMeasurementPool,
                sendThreadPtr.p->m_send_thread_50ms_measurements);
            list_50ms.last(sendThreadMeasurementPtr);
          } else if (req.tableId == Ndbinfo::CPUSTAT_1SEC_TABLEID) {
            jam();
            Local_SendThreadMeasurement_fifo list_1sec(
                c_sendThreadMeasurementPool,
                sendThreadPtr.p->m_send_thread_1sec_measurements);
            list_1sec.last(sendThreadMeasurementPtr);
          } else if (req.tableId == Ndbinfo::CPUSTAT_20SEC_TABLEID) {
            jam();
            Local_SendThreadMeasurement_fifo list_20sec(
                c_sendThreadMeasurementPool,
                sendThreadPtr.p->m_send_thread_20sec_measurements);
            list_20sec.last(sendThreadMeasurementPtr);
          } else {
            ndbabort();
            return;
          }

          pos = (sendThreadMeasurementPtr.i << 16) + (pos_thread_id << 8) + 0;
        } else if (pos_thread_id == 0) {
          if (measurePtr.i == RNIL) {
            jam();
            g_eventLogger->info("measurePtr.i = RNIL");
            ndbassert(false);
            ndbinfo_send_scan_conf(signal, req, rl);
            return;
          }
          if (req.tableId == Ndbinfo::CPUSTAT_50MS_TABLEID) {
            jam();
            c_next_50ms_measure.prev(measurePtr);
            if (measurePtr.i == RNIL) {
              jam();
              c_next_50ms_measure.first(measurePtr);
            }
          } else if (req.tableId == Ndbinfo::CPUSTAT_1SEC_TABLEID) {
            jam();
            c_next_1sec_measure.prev(measurePtr);
            if (measurePtr.i == RNIL) {
              jam();
              c_next_1sec_measure.first(measurePtr);
            }
          } else if (req.tableId == Ndbinfo::CPUSTAT_20SEC_TABLEID) {
            jam();
            c_next_20sec_measure.prev(measurePtr);
            if (measurePtr.i == RNIL) {
              jam();
              c_next_20sec_measure.first(measurePtr);
            }
          } else {
            ndbabort();
            return;
          }
          pos = (measurePtr.i << 16) + (0 << 8) + pos_index + 1;
        } else {
          SendThreadPtr sendThreadPtr;
          ndbrequire(
              c_sendThreadRecordPool.getPtr(sendThreadPtr, pos_thread_id - 1));

          ndbrequire(sendThreadMeasurementPtr.i != RNIL);
          if (req.tableId == Ndbinfo::CPUSTAT_50MS_TABLEID) {
            Local_SendThreadMeasurement_fifo list_50ms(
                c_sendThreadMeasurementPool,
                sendThreadPtr.p->m_send_thread_50ms_measurements);
            list_50ms.prev(sendThreadMeasurementPtr);
            if (sendThreadMeasurementPtr.i == RNIL) {
              jam();
              list_50ms.first(sendThreadMeasurementPtr);
            }
          } else if (req.tableId == Ndbinfo::CPUSTAT_1SEC_TABLEID) {
            Local_SendThreadMeasurement_fifo list_1sec(
                c_sendThreadMeasurementPool,
                sendThreadPtr.p->m_send_thread_1sec_measurements);
            list_1sec.prev(sendThreadMeasurementPtr);
            if (sendThreadMeasurementPtr.i == RNIL) {
              jam();
              list_1sec.first(sendThreadMeasurementPtr);
            }
          } else if (req.tableId == Ndbinfo::CPUSTAT_20SEC_TABLEID) {
            Local_SendThreadMeasurement_fifo list_20sec(
                c_sendThreadMeasurementPool,
                sendThreadPtr.p->m_send_thread_20sec_measurements);
            list_20sec.prev(sendThreadMeasurementPtr);
            if (sendThreadMeasurementPtr.i == RNIL) {
              jam();
              list_20sec.first(sendThreadMeasurementPtr);
            }
          } else {
            ndbabort();
            return;
          }
          pos = (sendThreadMeasurementPtr.i << 16) + (pos_thread_id << 8) +
                pos_index + 1;
        }

        if (rl.need_break(req)) {
          jam();
          ndbinfo_send_scan_break(signal, req, rl, pos);
          return;
        }
      }
      break;
    }
    case Ndbinfo::CPUSTAT_TABLEID: {
      Uint32 pos = cursor->data[0];

      SendThreadMeasurementPtr sendThreadMeasurementPtr;
      MeasurementRecordPtr measurePtr;

      for (;;) {
        if (pos == 0) {
          jam();
          MeasurementRecord measure;
          bool success = calculate_cpu_load_last_second(&measure);
          ndbrequire(success);
          Ndbinfo::Row row(signal, req);
          row.write_uint32(getOwnNodeId());
          row.write_uint32(getThreadId());

          if (measure.m_elapsed_time) {
            jam();
            Uint64 user_os_percentage =
                ((Uint64(100) * measure.m_user_time_os) + Uint64(500 * 1000)) /
                measure.m_elapsed_time;

            Uint64 kernel_percentage =
                ((Uint64(100) * measure.m_kernel_time_os) +
                 Uint64(500 * 1000)) /
                measure.m_elapsed_time;

            /* Ensure that total percentage reported is always 100% */
            if (user_os_percentage + kernel_percentage > Uint64(100)) {
              kernel_percentage = Uint64(100) - user_os_percentage;
            }
            Uint64 idle_os_percentage =
                Uint64(100) - (user_os_percentage + kernel_percentage);
            row.write_uint32(Uint32(user_os_percentage));
            row.write_uint32(Uint32(kernel_percentage));
            row.write_uint32(Uint32(idle_os_percentage));

            Uint64 exec_time = measure.m_exec_time_thread;
            Uint64 spin_time = measure.m_spin_time_thread;
            Uint64 buffer_full_time = measure.m_buffer_full_time_thread;
            Uint64 send_time = measure.m_send_time_thread;

            Uint64 non_exec_time = spin_time + send_time + buffer_full_time;
            if (unlikely(non_exec_time > exec_time)) {
              exec_time = 0;
            } else {
              exec_time -= non_exec_time;
            }

            Uint64 exec_percentage =
                ((Uint64(100) * exec_time) + Uint64(500 * 1000)) /
                measure.m_elapsed_time;

            Uint64 spin_percentage =
                ((Uint64(100) * spin_time) + Uint64(500 * 1000)) /
                measure.m_elapsed_time;

            Uint64 send_percentage =
                ((Uint64(100) * send_time) + Uint64(500 * 1000)) /
                measure.m_elapsed_time;

            Uint64 buffer_full_percentage =
                ((Uint64(100) * buffer_full_time) + Uint64(500 * 1000)) /
                measure.m_elapsed_time;

            /* Ensure that total percentage reported is always 100% */
            Uint64 exec_full_percentage =
                exec_percentage + buffer_full_percentage;
            Uint64 exec_full_send_percentage =
                exec_percentage + buffer_full_percentage + send_percentage;
            Uint64 all_exec_percentage = exec_percentage +
                                         buffer_full_percentage +
                                         send_percentage + spin_percentage;
            Uint64 sleep_percentage = 0;
            if (buffer_full_percentage > Uint64(100)) {
              buffer_full_percentage = Uint64(100);
              exec_percentage = 0;
              send_percentage = 0;
              spin_percentage = 0;
            } else if (exec_full_percentage > Uint64(100)) {
              exec_percentage = Uint64(100) - buffer_full_percentage;
              send_percentage = 0;
              spin_percentage = 0;
            } else if (exec_full_send_percentage > Uint64(100)) {
              exec_percentage = Uint64(100) - exec_full_percentage;
              spin_percentage = 0;
            } else if (all_exec_percentage > Uint64(100)) {
              exec_percentage = Uint64(100) - exec_full_send_percentage;
            } else {
              sleep_percentage = Uint64(100) - all_exec_percentage;
            }
            ndbrequire(exec_percentage + buffer_full_percentage +
                           send_percentage + spin_percentage +
                           sleep_percentage ==
                       Uint64(100));

            row.write_uint32(Uint32(exec_percentage));
            row.write_uint32(Uint32(sleep_percentage));
            row.write_uint32(Uint32(spin_percentage));
            row.write_uint32(Uint32(send_percentage));
            row.write_uint32(Uint32(buffer_full_percentage));

            row.write_uint32(Uint32(measure.m_elapsed_time));
          } else {
            jam();
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
          }

          ndbinfo_send_row(signal, req, row, rl);
          if (instance() != m_main_thrman_instance || m_num_send_threads == 0) {
            jam();
            break;
          }
          pos++;
        } else {
          /* Send thread CPU load */
          jam();
          if ((pos - 1) >= m_num_send_threads) {
            jam();
            g_eventLogger->info("send instance out of range");
            ndbassert(false);
            ndbinfo_send_scan_conf(signal, req, rl);
            return;
          }
          SendThreadMeasurement measure;
          bool success =
              calculate_send_thread_load_last_second(pos - 1, &measure);
          if (!success) {
            g_eventLogger->info(
                "Failed calculate_send_thread_load_last_second");
            ndbassert(false);
            ndbinfo_send_scan_conf(signal, req, rl);
            return;
          }
          Ndbinfo::Row row(signal, req);
          row.write_uint32(getOwnNodeId());
          row.write_uint32(m_num_threads + (pos - 1));

          if (measure.m_elapsed_time_os == 0) {
            jam();
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
          } else {
            Uint64 user_time_os_percentage =
                ((Uint64(100) * measure.m_user_time_os) + Uint64(500 * 1000)) /
                measure.m_elapsed_time_os;

            row.write_uint32(Uint32(user_time_os_percentage));

            Uint64 kernel_time_os_percentage =
                ((Uint64(100) * measure.m_kernel_time_os) +
                 Uint64(500 * 1000)) /
                measure.m_elapsed_time_os;

            row.write_uint32(Uint32(kernel_time_os_percentage));

            Uint64 idle_time_os_percentage =
                ((Uint64(100) * measure.m_idle_time_os) + Uint64(500 * 1000)) /
                measure.m_elapsed_time_os;

            row.write_uint32(Uint32(idle_time_os_percentage));
          }

          if (measure.m_elapsed_time > 0) {
            Uint64 exec_time = measure.m_exec_time;
            Uint64 spin_time = measure.m_spin_time;
            Uint64 sleep_time = measure.m_sleep_time;

            exec_time -= spin_time;

            Uint64 exec_percentage =
                ((Uint64(100) * exec_time) + Uint64(500 * 1000)) /
                measure.m_elapsed_time;

            Uint64 sleep_percentage =
                ((Uint64(100) * sleep_time) + Uint64(500 * 1000)) /
                measure.m_elapsed_time;

            Uint64 spin_percentage =
                ((Uint64(100) * spin_time) + Uint64(500 * 1000)) /
                measure.m_elapsed_time;

            row.write_uint32(Uint32(exec_percentage));
            row.write_uint32(Uint32(sleep_percentage));
            row.write_uint32(Uint32(spin_percentage));
            row.write_uint32(Uint32(exec_percentage));
            row.write_uint32(Uint32(0));
            row.write_uint32(Uint32(measure.m_elapsed_time));
          } else {
            jam();
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
            row.write_uint32(0);
          }
          ndbinfo_send_row(signal, req, row, rl);

          if (pos == m_num_send_threads) {
            jam();
            break;
          }
          pos++;
        }
        if (rl.need_break(req)) {
          jam();
          ndbinfo_send_scan_break(signal, req, rl, pos);
          return;
        }
      }
      break;
    }
    default:
      break;
  }

  ndbinfo_send_scan_conf(signal, req, rl);
}