• Skip to main content
  • Skip to search
  • Skip to footer
Cadence Home
  • This search text may be transcribed, used, stored, or accessed by our third-party service providers per our Cookie Policy and Privacy Policy.

  1. Community Forums
  2. Custom IC SKILL
  3. How to start these jobs one after another

Stats

  • Locked Locked
  • Replies 9
  • Subscribers 143
  • Views 18632
  • Members are here 0
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How to start these jobs one after another

acom
acom over 9 years ago

Hello , 

I have 2 jobs which are needed to be run one after another automatically.But i didn't know how to tell skill that  job1 has been finished and you could  begin job2.

The only signal is that when job1 is done, there is a job1ResultFile which contains words "job1 run successfully." Is it possible to let job2 to recieve the signal as the start signal? It is a little hard to use ipcSleep.Because the running time of job1 varies from cell level to chip level for us.And it seems like that job1 cann't be used as the childprocess of ipcBeginProcess either.

I have given some tries like below:

job1~>job2

I check the running status of job1 manually to make sure it ends.  Then input the below command, Job2 begins successfully.

ipcBeginProcess("grep 'job1 run successfully' job1ResultFile "" 'LAYdatahandle nil 'Job2 "")

But it fails, when i submit job1 and the sentence together.it seems like that at the moment i submit job1, the job1ResultFile has not been gotten compelely.

  • Cancel
  • Andrew Beckett
    Andrew Beckett over 9 years ago

    I assume you're talking about two simulation jobs? Are you using ADE L or XL? Is this from OCEAN? Which version of Virtuoso are  you using? In distributed mode (if it's ADE) are you using "queue" or "command" mode?

    Lots of questions, which is why the forum guidelines ask you to provide this kind of background information, otherwise it's hard to guess what you're actually doing and what the right answer might be.

    Regards,

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • acom
    acom over 9 years ago

    Hello Andrew,

    Here it is my detailed information.

    Background :

    we have a skill gui which helps us to intergrate 3 steps based on calibre drc.That is ,In the skill gui, we have already intergrated 3 steps(that is (1)calibre -drc step1; (2)calibre -drc step2;(3)calibre -drc step3).By clicking button 1 manually in the gui, we could submit the job1 (calibre -drc step1) into the remote server.The same for step2 and step3.Now we would like to run these 3 steps one after another automatically.

    The virtuoso we are using is 6.1.6.14.

    Issues: 

    I am thinking whether it is possible for us to fullfill this kind of automation by skill too.( we could manuplate the gui button by skill script).But the difficult part is that how we could know step1 (calibre -drc step1)has been done.The only signal is that there is some file job1ResultFile which contains words "job1 run successfully" when it is done.  

    Examples:

    step 1: calibre -drc step1;

    step 2 :calibre -drc step2

    step 3: calibre -drc step3

    Base on the skill gui, submit step1 in machine 1~>Base on the skill gui, submit step1 in machine 2~>Base on the skill gui, submit step3 in machine 3.

    Is there any way for skill to know :

    yes, step 1 has been done because i could got the sentence  "job1 run successfully"  in   job1ResultFile.Now i could start step2.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 9 years ago

    You can do this with the postFunc argument to ipcBeginProcess - to chain the various submissions. To make this simpler, I wrote the code below which can be seen as a little package for job submission. It's not very well tested, but I wrote it in C-syntax rather than my usual LISP syntax to make it easier for others to understand. Note that the file must have a .ils suffix for this to work properly.

    To use it:

    step1=abSubmitJob("calibre -drc step1")
    step2=abSubmitJob("calibre -drc step2" ?dependency step1)
    step3=abSubmitJob("calibre -drc step3" ?dependency step2)

    Regards,

    Andrew.

    /* abSubmitJob.ils
    
    Author     A.D.Beckett
    Group      Custom IC (UK), Cadence Design Systems Ltd.
    Language   SKILL
    Date       Jun 20, 2016 
    Modified   Aug 28, 2018 
    By         A.D.Beckett
    
    Function to submit a job with dependencies. For
    example of usage, look at the test functions near
    the end.
    
    Main functions to use:
    
    ; submit a job - similar args to ipcBeginProcess, but keyword
    ; arguments - plus there's a ?dependency to say that a job is
    ; dependent upon an earlier job completing.
    abSubmitJob(command @key (host "") dataHandler errHandler
             postFunc (logFile "") dependency)           
    ; can be called within an exit handler (postFunc) to cancel
    ; any subsequent jobs
    abCancelSubsequentJobs()
    
    ***************************************************
    
    SCCS Info: @(#) abSubmitJob.ils 08/29/18.00:11:33 1.2
    
    */
    
    ;------------------------------------------------------------------------
    ; Data structure to keep track of a job
    ;------------------------------------------------------------------------
    defstruct(abSubmitJobData ipcId dependencies command host dataHandler
        errHandler postFunc logFile)
    
    let(((jobTable makeTable('jobs nil)) (newJobId 1))
        /***************************************************************
        *                                                              *
        *   Global function to submit a job. Uses keyword arguments    *
        *     rather than optional positional arguments, but other     *
        *   than that looks like ipcBeginProcess, with the addition    *
        *      of a ?dependency argument to allow dependent jobs       *
        *                                                              *
        *  abSubmitJob(command @key (host "") dataHandler errHandler   *
        *              postFunc (logFile "") dependency)               *
        *                                                              *
        ***************************************************************/
        globalProc(abSubmitJob(command @key (host "") dataHandler errHandler 
                postFunc (logFile "") dependency)
            let((newJob)
                newJob=make_abSubmitJobData(?ipcId nil ?dependencies nil
                    ?command command ?host host ?dataHandler dataHandler 
                    ?errHandler errHandler ?postFunc postFunc ?logFile logFile
                )
                jobTable[newJobId]=newJob
                if(jobTable[dependency] then
                    jobTable[dependency]->dependencies=cons(newJobId 
                        jobTable[dependency]->dependencies)
                else
                    newJob->ipcId=ipcBeginProcess(command host dataHandler 
                        errHandler 
                        getFinishedHandler(newJobId)
                        logFile
                    )
                )
                ;debugJobTable()
                newJobId++
            )
        )
        /***************************************************************
        *                                                              *
        *                       debugJobTable()                        *
        *                                                              *
        * Local function (if needed) for debugging the contents of the *
        *                          job table                           *
        *                                                              *
        ***************************************************************/
        procedure(debugJobTable()
            foreach(jobId jobTable
                printf("%d: %L\n" jobId jobTable[jobId]->??)
            )
        )
        /***************************************************************
        *                                                              *
        *                 abSubmitJobGetIpcID(jobNum)                  *
        *                                                              *
        *             Given a job number, return the ipcId             *
        *                                                              *
        ***************************************************************/
        globalProc(abSubmitJobGetIpcID(jobNum)
            jobTable[jobNum]->ipcId
        )
        /***************************************************************
        *                                                              *
        *                 cancelSubsequentJobs(jobNum)                 *
        *                                                              *
        *  Local function that given a job number, remove all the jobs *
        *               that are dependent upon this one.              *
        *                                                              *
        ***************************************************************/
        procedure(cancelSubsequentJobs(jobNum)
            let((job)
                job=jobTable[jobNum]
                when(job
                    foreach(dependency job->dependencies
                        cancelSubsequentJobs(dependency)
                    )
                    job->dependencies=nil
                    remove(jobNum jobTable)
                )
            )
        )
        /***************************************************************
        *                                                              *
        *   Local function to get the exit handler - wrapped so that   *
        *        can get the job number from the lexical scope         *
        *                                                              *
        *                  getFinishedHandler(jobNum)                  *
        *                                                              *
        ***************************************************************/
        procedure(getFinishedHandler(jobNum)
            procedure(exitHandler(id status)
                jobFinished(jobNum id status)
            )
            exitHandler
        )
        /***************************************************************
        *                                                              *
        * Local function to track job finishing. Takes care of calling *
        *  the specified exit handler, plus submitting any dependent   *
        *                            jobs.                             *
        *                                                              *
        *               jobFinished(jobNum ipcId status)               *
        *                                                              *
        ***************************************************************/
        procedure(jobFinished(jobNum ipcId status)
            let((job depJob)
                /***************************************************************
                *                                                              *
                *                   abCancelSubsequentJobs()                   *
                *                                                              *
                *      A function that can be called from an exit handler      *
                *           to cancel jobs dependent upon this one.            *
                *                                                              *
                ***************************************************************/
                ;------------------------------------------------------------
                ; in this scope to access the current job number
                ;------------------------------------------------------------
                globalProc(abCancelSubsequentJobs()
                    cancelSubsequentJobs(jobNum)
                )
                ;------------------------------------------------------------
                ; now finish the job - call the handler and then follow
                ; the dependencies
                ;------------------------------------------------------------
                job=jobTable[jobNum]
                when(job->postFunc
                    if(stringp(job->postFunc) then
                        errset(funcall(concat(job->postFunc) ipcId status) t)
                    else
                        errset(funcall(job->postFunc ipcId status) t)
                    )
                )
                foreach(dependency job->dependencies
                    depJob=jobTable[dependency]
                    if(depJob then
                        depJob->ipcId=ipcBeginProcess(
                            depJob->command 
                            depJob->host 
                            depJob->dataHandler 
                            depJob->errHandler 
                            getFinishedHandler(dependency)
                            depJob->logFile
                        )
                    else
                        warn("Couldn't find info for dependent job %L\n" dependency)
                    )
                )
                remove(jobNum jobTable)
            )
        )
        ;--------------------------------------------------------------------
        ; Test functions
        ;--------------------------------------------------------------------
        procedure(testDataHandler(ipcId data)
            printf("%L: %s\n" ipcId data)
        )
        procedure(testFinished(ipcId status)
            printf("%L: finished with status %d\n" ipcId status)
        )
        procedure(testFinishedAndCancel(ipcId status)
            unless(zerop(status)
                abCancelSubsequentJobs()
            )
            printf("%L: finished (and cancelled) with status %d\n" ipcId status)
        )
        globalProc(abSubmitJobTestSubmission()
            let((job1 job2 job3 job4)
                job1=abSubmitJob("sleep 30" ?postFunc testFinished)
                job2=abSubmitJob("sleep 2" ?dependency job1 
                    ?postFunc testFinishedAndCancel)
                job3=abSubmitJob("echo neg exit; exit -1" ?dependency job1 
                    ?postFunc testFinishedAndCancel)
                abSubmitJob("echo no dependency" ?postFunc testFinished
                    ?dataHandler testDataHandler)
                abSubmitJob("echo with dependency" ?postFunc testFinished
                    ?dataHandler testDataHandler ?dependency job1)
                abSubmitJob("echo with dependency proceed" ?postFunc testFinished
                    ?dataHandler testDataHandler ?dependency job2)
                ;------------------------------------------------------------
                ; these next two jobs shouldn't ever be invoked, because
                ; testFinishedAndCancel for job3 above will cancel then
                ;------------------------------------------------------------
                job4=abSubmitJob("echo with dependency cancelled" 
                    ?postFunc testFinished
                    ?dataHandler testDataHandler ?dependency job3)
                abSubmitJob("echo with dependency really cancelled" 
                    ?postFunc testFinished
                    ?dataHandler testDataHandler ?dependency job4)
                abSubmitJob("echo with bad dependency" ?postFunc testFinished
                    ?dataHandler testDataHandler ?dependency 314159265)
            )
        )
    )
    
    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • acom
    acom over 9 years ago

    Hello Andrew,

    Thanks for your reply here.I spend some time reading the script.

    But i don't queit understand some part.Could you help me to firgure out?(highlight in red )

    Take the Test functions for example.

    job1=abSubmitJob("sleep 30" ?postFunc testFinished)

    job2 =abSubmitJob("echo with dependency" ?postFunc testFinished ?dataHandler testDataHandler ?dependency job1)

    1) what is "jobTable[dependency]" ?

    step 1  when run job1,

    newJob =make_abSubmitJobData(?ipcId nil ?dependencies nil ?command "sleep 30" ?host "" ?dataHandler nil ?errHandler nil ?postFunc nil ?logFile "")

    jobTable[1]=newJob 

    jobTable[dependency] ;;; Does jobTable[dependency]  equal to "jobTable[nil] " ? That is, default value of jobTab = nil ?

    The return value of abSubmitJob("sleep 30" ?postFunc testFinished) is 2(ie. newJobId++),right?

    After all, step 1 is running...

    step 2  when run job2,

    newJob=make_abSubmitJobData(?ipcId nil ?dependencies nil ?command "echo with dependency" ?host "" ?dataHandler nil ?errHandler nil ?postFunc nil ?logFile "")

    jobTable[2]=newJob

    jobTable[dependency]];;; Does this equal "jobTable[2] "

    jobTable[dependency]->dependencies=cons(newJobId jobTable[dependency]->depedencies);;;  Does  this equal " jobTable[2]->dependencies= list(2)"?

    newJobId;;; Does newJobId equal to 3 ?De we jump out the function "job2 =abSubmitJob("echo with dependency" ?postFunc testFinished ?dataHandler testDataHandler ?dependency job1)"  at this point?

    After all, why step 2 knows to wait for step1?

    Thanks

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 9 years ago

    OK, first of all, newJobId++ will return 1 on the first call, not 2. It's a post increment operator which means that it returns the original value and then increments it. 

    For step 2, ?dependency would have been 1, and so jobTable[dependency] would find jobTable[1]. It then updates the list of jobs that are dependent upon job 1.

    So that's how it knows - for each job id (which is just an integer) it maintains a list of dependent jobs, so that when the job finishes, it can look at that list and actually start them all.

    Rather than trying to understand the test code (where you can't see the values - it was there for my testing purposes), I suggest  you just try doing this:

    procedure(finished(id status)
      printf("ID: %L finished\n" id)
    )
    step1=abSubmitJob("sleep 10" ?postFunc 'finished)
    step2=abSubmitJob("sleep 15" ?dependency step1 ?postFunc 'finished)
    step3=abSubmitJob("sleep 5" ?dependency step2 ?postFunc 'finished)

    Then you can look at the values of step1, step2, step3 etc.

    Regards,

    Andrew.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • acom
    acom over 9 years ago
    It works.Thanks Andrew
    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Purge2343
    Purge2343 over 5 years ago in reply to Andrew Beckett

    Hi 

    I run the following job in cadence gui to get the post lpe netlist and lvs information. I would like to know if how can submit this as a job in the following skill command. 

    deOpenCellView("mylibrary" "mydesign" "layout" "maskLayout" nil "r" )
    d2qDfIIqviCB(geGetWindowCellView())
    hiiSetCurrentForm('d2q_TaskSelect_mylibrary_mydesign_layout)
    d2q_TaskSelect_mylibrary_mydesign_layout->d2q_lpe_task_name->value= t
    d2q_TaskSelect_mylibrary_mydesign_layout->d2q_lvs_task_name->value= t
    hiFormDone(d2q_TaskSelect_mylibrary_mydesign_layout)
    d2qStatusCB( "mylibrary" "mydesign" "layout" 'executeAll )

    thank you 

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 5 years ago in reply to Purge2343

    Please read the forum guidelines. They ask you not to post on the end (or in this case in the middle) of an old thread. I've no idea what these d2q functions are or what they do - I don't believe they are Cadence-supplied functions as far as I know.

    Andrew.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Purge2343
    Purge2343 over 5 years ago in reply to Andrew Beckett

    Thank you, I will create the new thread. 

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel

Community Guidelines

The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.

© 2025 Cadence Design Systems, Inc. All Rights Reserved.

  • Terms of Use
  • Privacy
  • Cookie Policy
  • US Trademarks
  • Do Not Sell or Share My Personal Information