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

Asked

Viewed 328 times

10

I have the following code in ADVPL:

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

    dbSelectArea("ZX1")
    ZX1->(dbSetOrder(1))
    ZX1->(dbGoTop())
    ZX1->(dbSeek(cChave))

    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)) + '",'
                EndIf
            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))) + '",'
            EndIf
        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 += ""
        EndIf
        ZX1->(dbSkip())
    EndDo
    ZX1->(dbCloseArea())

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

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

Your unique 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 the iteration in ZX1 to redeem the same information in 80,000 lines of the same query have some weight in performance, but I do not know any profiler to be sure of how much is being dedicated to that particular piece of code. I have no security to make time measurement within the code without that measurement does not change the measurement object and its measurement.

For the iteration in ZX1, I refer to the whole process, since the initialization with dbSelectArea("ZX1") up to the teardown of the tie with ZX1-> (dbCloseArea())

Another point of doubt I have about performance is about substrings, in that passage: 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 don’t know profiler to do so, and this time I have no knowledge of how to measure from within the memory code used, called garbage collectors or fragmentation.

So I repeat my question of the title:

How to analyze the performance impact of a code snippet?

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

  • 1

    @Bacco, yes, I couldn’t see how to solve this macro (&(conv2Json(ZX1->ZX1_CP_PRO, cTabela))) statically without having to interpret this piece of code... but something tells me there are other bottlenecks that are easier to remove

1 answer

7


Superficially analyzing the code, whether it is STATIC FUNCTION linhaJson() is often called, from within the same execution context, REMOVE lines : ZX1->(dbGoTop()) e ZX1->(dbCloseArea()). You don’t need to open and close the alias ZX1 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 measure the time spent by this function, and the calls coming from within it, the best alternative is to use the Profiler of Advpl. For now, check on TDN at link How to Run a Profiler. Although in that way the log generated will generate information about the entire routine, the analysis of the console.log Protheus Server generated after routine execution allows you to identify which functions were called from which source point, including all function calls LinhaJson(), and all calls from functions called from within it.

  • That one linhaJson is called several times, guaranteed. Then, in that case, assuming I continue doing the while about ZX1->EOF() .OR. cChave == ZX1->(...), with that ZX1->dbSkip() at the end of this loop, how to ensure that the ZX1 be at the same location the next time linhaJson was called? About the profiler, as soon as possible I will try to run it to identify the hotspots, really did not know this TDN.

  • Great automan! rs Take my +1. :)

  • 1

    @Jeffersonquesado, if the ZX1 table is not changed during processing, and you have a high incidence of repeat cChave parameter, you could cache it using a STATIC array, just for the last processed key. For example, in three consecutive function calls where cChave was not changed, the next calls would not IO with Dbaccess. I hope I’ve helped.

  • I’ve successfully done the Profiling (but unfortunately I could not do using the linhaJson above described; I had difficulties configuring the test environment, but this is not the case). I’m having some difficulty understanding everything about the exit from profiler, I find the documentation of Totvs very confusing. Do you have any TDN related to the subject? Or do you think I should post a new question with the relevant information from Profiling?

  • @Jeffersonquesado, there is a richer documentation in detail in TDN, but it is not with public access released -- it is restricted to TOTVS participants. A good alternative is to use a TDS tool, which is capable of generating and analyzing the Profiler execution -- see link http://tdn.totvs.com/pages/viewpage.action?pageId=24347198

  • @siga0984, I even got to this page, but I could not extract from it the information that was wanted to me. All the information it shows in the IDE prints I was able to discern/calculate from the log of profiler, but some things don’t (yes, I ended up creating the question =P). Ah, I’d rather use the Killerall plugin for Vscode than tinker with this TDS derived from Eclipse, it’s more intuitive and easy to work with.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.