How to analyze performance impact of a code snippet in ADVPL?


I have the following code in ADVPL:

Static Function linhaJson(cTabela, cChave, lVerificaExclusao)
    local cTipo
    local xResult
    local cJson := "{"


    While !(ZX1->(EOF())) .AND. cChave == ZX1->(ZX1_FILIAL + ZX1_COD)
        If ZX1->ZX1_TIPO == 'B'
            xResult := &(conv2Json(ZX1->ZX1_CP_PRO, cTabela))
            cTipo := ValType(xResult)//ValType(ZX1->ZX1_CP_PRO) 
            If cTipo == 'C'
                if AllTrim(xResult) != "NULL"
                    cJson += '"' + AllTrim(Lower(ZX1->ZX1_CP_GEO)) + '":"' + ESCENVST(SUBS(AllTrim(xResult),1,ZX1->ZX1_TAM)) + '",'
            ElseIf cTipo == 'N'
                cJson += '"' + AllTrim(Lower(ZX1->ZX1_CP_GEO)) + '":"' + AllTrim(STR(&(cTabela + "->"+ZX1->ZX1_CP_PRO))) + '",'
            ElseIf cTipo == 'D'
                cJson += '"' + AllTrim(Lower(ZX1->ZX1_CP_GEO)) + '":"' + AllTrim(DtoS(&(cTabela + "->"+ZX1->ZX1_CP_PRO))) + '",'
        ElseIf ZX1->ZX1_TIPO == 'S'
            cJson += '"' + AllTrim(Lower(ZX1->ZX1_CP_GEO)) + '":"' + AllTrim(ZX1->ZX1_CP_PRO) + '",'
        ElseIf ZX1->ZX1_TIPO == 'V'
            cJson += '"' + AllTrim(Lower(ZX1->ZX1_CP_GEO)) + '":"",'
        Else //ZX1->ZX1_TIPO == 'N'
            cJson += ""

    cJson := SUBS(cJson, 1, len(cJson) - 1)

    If lVerificaExclusao //Se for excluso
        cJson += ',"data_delete":"' + getCurrentDate() + '" '
    cJson += "}"
Return cJson

Its only obligation is to mine data from a query in Protheus and turn it into a JSON for me to consume on my server. It runs for every line of every mining I do.

I believe that the iteration in ZX1 to retrieve the same information in 80,000 rows of the same query has some weight in the performance, however I do not know any profiler to be sure of how much is being dedicated to this particular code snippet. I do not have the security to measure time within the code without this measurement does not change the measurement object and its measurement.


By iteration in ZX1 , I mean the whole process, from the initialization with dbSelectArea("ZX1") to the teardown of the loop with ZX1-> (dbCloseArea())

Another point of doubt I have about performance is about substrings , in this section: cJson := SUBS(cJson, 1, len(cJson) - 1) . This could generate some memory fragmentation allocated to the strings more than I'm already fragmenting. Again, I do not know profiler to do so, and this time I am not aware of how to measure from memory used code, called garbage collector or fragmentation.

So, I reiterate my title question:

How to analyze the performance impact of a code snippet?

The intention here is to avoid doing any unnecessary refactoring in the code, which in the end has little gain and is difficult to do. Just to change the hotspots of the code snippet.

asked by anonymous 19.11.2018 / 19:22

1 answer


By analyzing the code superficially, if this STATIC FUNCTION rowJson () is often called from within the same execution context, REMOVE the lines: ZX1-> (dbGoTop ()) and ZX1-> (dbCloseArea () ). You do not need to open and close the ZX1 alias with each loop. This will already give you one with performance gain, blindfolded. And also do not need to position in the first order record to make a DBSeek ().

Now, to evaluate the time spent by this function, and by calls coming from within it, the best alternative is to use the AdvPL Profiler. For an hour, see TDN at How to run a Profiler . Although in this way the generated log generates information about the entire routine, the analysis of the console.log of the Protheus Server generated after the execution of the routine allows to identify which functions were called from that point of the source, including all calls of the LineJson function (), and all calls from functions called from within it.

22.11.2018 / 02:15