code: def main_loop(args):
      """main loop logic for trial runner"""
      idle_last_time = datetime.now()
      gpu_refresh_last_time = datetime.now() - timedelta(minutes=1)
      try:
          if args.job_pid_file:
              with open(args.job_pid_file, "w") as job_file:
                  job_file.write("%d" % os.getpid())
  
          trials = dict()
  
          command_channel = args.command_channel
          # command loop
          while True:
              command_type, command_data = command_channel.receive()
              if command_type == CommandType.NewTrialJob:
                  trial_id = command_data["trialId"]
                  if trial_id in trials.keys():
                      trial = trials[trial_id]
                      if trial.is_running():
                          raise Exception(
                              "trial %s is running already, cannot start a new one"
                              % trial.id
                          )
                      else:
                          del trials[trial_id]
                  trial = Trial(args, command_data)
                  trial.run()
                  trials[trial_id] = trial
              elif command_type == CommandType.KillTrialJob:
                  trial_id = command_data
                  if trial_id in trials.keys():
                      trial = trials[trial_id]
                      trial.kill(command_data)
              elif command_type == CommandType.SendTrialJobParameter:
                  trial_id = command_data["trialId"]
                  if trial_id in trials.keys():
                      trial = trials[trial_id]
                      trial.save_parameter_file(command_data)
              elif command_type is not None:
                  raise Exception("unknown command %s" % command_type)
  
              trial_list = list(trials.values())
              for trial in trial_list:
                  if trial is not None and trial.is_running():
                      idle_last_time = datetime.now()
                  else:
                      del trials[trial.id]
  
              if (
                  datetime.now() - idle_last_time
              ).seconds > idle_timeout_seconds:
                  nni_log(
                      LogType.Info,
                      "trial runner is idle more than {0} seconds, so exit.".format(
                          idle_timeout_seconds
                      ),
                  )
                  break
  
              if (
                  args.enable_gpu_collect
                  and (datetime.now() - gpu_refresh_last_time).seconds
                  > gpu_refressh_interval_seconds
              ):
                  # collect gpu information
                  gpu_info = collect_gpu_usage(args.node_id)
                  command_channel.send(
                      CommandType.ReportGpuInfo, gpu_info
                  )
                  gpu_refresh_last_time = datetime.now()
              time.sleep(0.5)
      except Exception as ex:
          traceback.print_exc()
          raise ex
      finally:
          nni_log(LogType.Info, "main_loop exits.")
  
          trial_list = list(trials.values())
          for trial in trial_list:
              trial.kill()
              del trials[trial.id]
          # wait to send commands
          for _ in range(10):
              if command_channel.sent():
                  break
              time.sleep(1)
          command_channel.close()
  
file_path: nni/nni/tools/trial_tool/trial_runner.py
imports: import argparse
  import json
  import os
  import random
  import re
  import sys
  import time
  import traceback
  from datetime import datetime, timedelta
  import pkg_resources
  from .gpu import collect_gpu_usage
label_desc: Use image node_id 1 for calling a global function with example usage: main_loop(args) without return types