Search code examples
ctcllsf

High CPU Utilization(~100%) while runing Tcl_DoOneEvent using LSF/bsub infrastructure


I have created my own event loop in Tcl as below. When i run the below code using tclsh interactively, CPU Utilization is close to 0% and when i run the same run using bsub, CPU Utilization shoots up to 100%.

I have even tried making read call blocking using below and that doesn't help too.

int flag = fcntl(0, F_GETFL);
flag = flag & (~O_NONBLOCK);
(void) fcntl(0, F_SETFL, (long)flag);

What is the reason here and how do i solve this problem?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <tcl.h>
#include <errno.h>
#include <fcntl.h>

void fwStdinKeyHandler(ClientData clientData, int mask)
{
  unsigned char c = 0;
  int rc = read(STDIN_FILENO, &c, 1);
  //printf("rc is : %d\n",rc);
  while (rc < 1 && errno == EINTR) {}
}


static void MainLoop(void)
{
  Tcl_CreateFileHandler(STDIN_FILENO, TCL_READABLE, fwStdinKeyHandler,    NULL);
  while (1) {
    Tcl_DoOneEvent(0);
  }
  fprintf(stdout,"Exit MainLoop\n");
  fflush(stdout);
}

static int Hello_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
  Tcl_SetMainLoop(MainLoop);
  return TCL_OK;
}

 /*
  * Hello_Init -- Called when Tcl loads your extension.
  */
int DLLEXPORT  Cmd_Init(Tcl_Interp *interp)
{
  if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
    return TCL_ERROR;
  }
  /* changed this to check for an error - GPS */
  if (Tcl_PkgProvide(interp, "Hello", "1.0") == TCL_ERROR) {
    return TCL_ERROR;
  }
  Tcl_CreateObjCommand(interp, "doone_loop", Hello_Cmd, NULL, NULL);
  return TCL_OK;
}

How to make?
1. File saved in,say, hello.c
2. gcc -fpic -c hello.c -I/usr/local/include
3. gcc -shared hello.o -o libcmd.so

How to run?
runme file contains:
load libcmd.so
doone_loop

/usr/bin/tclsh runme => CPU Utilization close to 0%
bsub -q interactive -m "/usr/bin/tclsh runme" => CPU Utilization close to 100%


Solution

  • For non-interactive shell, there is no terminal and hence, no stdin channel, so read call returns zero. So, we need to add below code in fwStdinkeyhandler after read returns 0.

    if(rc==0) {
       Tcl_DeleteFileHandler(0); 
    }