News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

onnx parser test

Started by guga, August 13, 2023, 07:54:03 AM

Previous topic - Next topic

guga

A small test on onnx library for Rosasm

I made a wrapper of the major onnx functions to make it easier to work with

Attached file without onnx models (need rosasm to open). The necessary dlls are a bit big to upload here, so i posted them also in other file in mega.

Complete version - https://mega.nz/file/Pth0SSwA#7W9qmjeDpsOdUGOivaSnLWLSrxB_ILAS4ZFbUIlaOTE
Executable and Dlls only - https://mega.nz/file/u9QSjR7T#PbMuBhP6QzKVNX9UIZCIvbO1aJ44gJcGuoH87wl90XY
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jj2007

I had to look it up - interesting :thumbsup:

Do you have a concrete example or application in mind?

guga

Hi JJ

Not yet (Just the ones i posted - attached here and in the links from mega). I was working on it but had to take a break to try to update RosAsm for the next release. I´m trying to make several major changes, including the ones related to the instring routines (that´s why i talked to you this week about this kind of function, because i´ll definitely need some faster instring functions to the next release)

The problem is that i didn´t updated rosasm since ages, and the last time Betov updated it (when he was active), there was still lots of bugs inside the code and RosAsm internalls are extremelly attached to the interface and still a bit buggy, what makes the updates a hell to do. So i´m trying to speed up and create the necessary dlls to make rosasm work more safelly and unlimited.

About the onnx, i did a small test last year (file attached here and also on the 1st post) that parsed a .onnx file, but the updated functions are the ones inside the file i provided earlier.

If you can´t open it in rosasm, i also uploaded the asm file of it (instead the exe embeded with the source).
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

Btw, on the attached files, you can do a small test similar to the C ones. You can draw a letter and it returns the overall percentage matching of that image


Btw, on the source code, i made 2 TITLE's (parts) related to the onnx api itself. One is called "TITLE OnnxHelpers"  that contains (for the moment) one single function to handle the onnx enviroment (SimpleCreateEnv) and other Title "TITLE OnnxCalling" that contains wrappers for all onnx functions (at least untill the version i used last year)

I made a serie of all wrappers such as:
        CreateStatus                                    GetErrorCode                GetErrorMessage             CreateEnv
        CreateEnvWithCustomLogger                       EnableTelemetryEvents       DisableTelemetryEvents      CreateSession
        CreateSessionFromArray                          RunModel                    CreateSessionOptions        SetOptimizedModelFilePath
        CloneSessionOptions                             SetSessionExecutionMode     EnableProfiling             DisableProfiling
        EnableMemPattern                                DisableMemPattern           EnableCpuMemArena           DisableCpuMemArena
        SetSessionLogId                                 SetSessionLogVerbosityLevel SetSessionLogSeverityLevel  SetSessionGraphOptimizationLevel
        SetIntraOpNumThreads                            SetInterOpNumThreads        CreateCustomOpDomain        CustomOpDomain_Add
        AddCustomOpDomain                               RegisterCustomOpsLibrary    SessionGetInputCount        SessionGetOutputCount
        SessionGetOverridableInitializerCount           SessionGetInputTypeInfo     SessionGetOutputTypeInfo    SessionGetOverridableInitializerTypeInfo
        SessionGetInputName                             SessionGetOutputName        SessionGetOverridableInitializerName    CreateRunOptions
        RunOptionsSetRunLogVerbosityLevel               RunOptionsSetRunLogSeverityLevel    RunOptionsSetRunTag     RunOptionsGetRunLogVerbosityLevel
        RunOptionsGetRunLogSeverityLevel                RunOptionsGetRunTag                 RunOptionsSetTerminate  RunOptionsUnsetTerminate
        CreateTensorAsOrtValue                          CreateTensorWithDataAsOrtValue      IsTensor                GetTensorMutableData
        FillStringTensor                                GetStringTensorDataLength   GetStringTensorContent      CastTypeInfoToTensorInfo
        GetOnnxTypeFromTypeInfo                         CreateTensorTypeAndShapeInfo    SetTensorElementType    SetDimensions
        GetTensorElementType                            GetDimensionsCount          GetDimensions               GetSymbolicDimensions
        GetTensorShapeElementCount                      GetTensorTypeAndShape       GetTypeInfo             GetValueType
        CreateMemoryInfo                                CreateCpuMemoryInfo             CompareMemoryInfo       MemoryInfoGetName
        MemoryInfoGetId                                 MemoryInfoGetMemType            MemoryInfoGetType       AllocatorAlloc
        AllocatorFree                                   AllocatorGetInfo                GetAllocatorWithDefaultOptions  AddFreeDimensionOverride
        GetValue                                        GetValueCount           CreateValue     CreateOpaqueValue
        GetOpaqueValue                                  KernelInfoGetAttribute_float    KernelInfoGetAttribute_int64    KernelInfoGetAttribute_string
        KernelContext_GetInputCount                     KernelContext_GetOutputCount    KernelContext_GetInput  KernelContext_GetOutput
        ReleaseEnv                                      ReleaseStatus      ReleaseMemoryInfo      ReleaseSession
        ReleaseValue                                    ReleaseRunOptions  ReleaseTypeInfo        ReleaseTensorTypeAndShapeInfo
        ReleaseSessionOptions                           ReleaseCustomOpDomain      GetDenotationFromTypeInfo       CastTypeInfoToMapTypeInfo
        CastTypeInfoToSequenceTypeInfo                  GetMapKeyType       GetMapValueType     GetSequenceElementType
        ReleaseMapTypeInfo                              ReleaseSequenceTypeInfo        SessionEndProfiling     SessionGetModelMetadata
        ModelMetadataGetProducerName                    ModelMetadataGetGraphName       ModelMetadataGetDomain      ModelMetadataGetDescription
        ModelMetadataLookupCustomMetadataMap            ModelMetadataGetVersion     ReleaseModelMetadata               CreateEnvWithGlobalThreadPools
        DisablePerSessionThreads                        CreateThreadingOptions      ReleaseThreadingOptions        ModelMetadataGetCustomMetadataMapKeys
        AddFreeDimensionOverrideByName                  GetAvailableProviders       ReleaseAvailableProviders       GetStringTensorElementLength
        GetStringTensorElement                          FillStringTensorElement     AddSessionConfigEntry       CreateAllocator
        ReleaseAllocator                                RunWithBinding      CreateIoBinding     ReleaseIoBinding
        BindInput                                       BindOutput          BindOutputToDevice  GetBoundOutputNames
        GetBoundOutputValues                            ClearBoundInputs    ClearBoundOutputs   TensorAt
        CreateAndRegisterAllocator                      SetLanguageProjection       SessionGetProfilingStartTimeNs      SetGlobalIntraOpNumThreads
        SetGlobalInterOpNumThreads                      SetGlobalSpinControl        AddInitializer      CreateEnvWithCustomLoggerAndGlobalThreadPools
        SessionOptionsAppendExecutionProvider_CUDA      SessionOptionsAppendExecutionProvider_ROCM      SessionOptionsAppendExecutionProvider_OpenVINO  SetGlobalDenormalAsZero
        CreateArenaCfg                                  ReleaseArenaCfg        ModelMetadataGetGraphDescription        SessionOptionsAppendExecutionProvider_TensorRT
        SetCurrentGpuDeviceId                           GetCurrentGpuDeviceId   KernelInfoGetAttributeArray_float   KernelInfoGetAttributeArray_int64
        CreateArenaCfgV2                                AddRunConfigEntry       CreatePrepackedWeightsContainer     ReleasePrepackedWeightsContainer
        CreateSessionWithPrepackedWeightsContainer      CreateSessionFromArrayWithPrepackedWeightsContainer     SessionOptionsAppendExecutionProvider_TensorRT_V2   CreateTensorRTProviderOptions
        UpdateTensorRTProviderOptions                   GetTensorRTProviderOptionsAsString      ReleaseTensorRTProviderOptions      EnableOrtCustomOps
        RegisterAllocator                               UnregisterAllocator     IsSparseTensor      CreateSparseTensorAsOrtValue
        FillSparseTensorCoo                             FillSparseTensorCsr     FillSparseTensorBlockSparse     CreateSparseTensorWithValuesAsOrtValue
        UseCooIndices                                   UseCsrIndices           UseBlockSparseIndices           GetSparseTensorFormat
        GetSparseTensorValuesTypeAndShape               GetSparseTensorValues           GetSparseTensorIndicesTypeShape     GetSparseTensorIndices
        HasValue                                        KernelContext_GetGPUComputeStream       GetTensorMemoryInfo     GetExecutionProviderApi
        SessionOptionsSetCustomCreateThreadFn           SessionOptionsSetCustomThreadCreationOptions        SessionOptionsSetCustomJoinThreadFn     SetGlobalCustomCreateThreadFn
        SetGlobalCustomThreadCreationOptions            SetGlobalCustomJoinThreadFn     SynchronizeBoundInputs      SynchronizeBoundOutputs
        SessionOptionsAppendExecutionProvider_CUDA_V2   CreateCUDAProviderOptions       UpdateCUDAProviderOptions       GetCUDAProviderOptionsAsString
        ReleaseCUDAProviderOptions                      SessionOptionsAppendExecutionProvider_MIGraphX      AddExternalInitializers     CreateOpAttr
        ReleaseOpAttr                                   CreateOp        InvokeOp        ReleaseOp
        SessionOptionsAppendExecutionProvider           CopyKernelInfo      ReleaseKernelInfo      GetTrainingApi
        SessionOptionsAppendExecutionProvider_CANN      CreateCANNProviderOptions       UpdateCANNProviderOptions       GetCANNProviderOptionsAsString
        ReleaseCANNProviderOptions]

The idea of the wrappers is build a dll to handle this. I need to document it completelly yet, but no time so far.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jj2007

Hi Guga,

To my old eyes, this looks even more cryptic than the MasmBasic source, so I'll reserve that when I will be reborn as a genius ;-)

You have a bit of work to do, it seems - good luck :thumbsup:

; General purpose macros:

[push | push #1 | #+1]  [pop | pop #1 | #+1]

[mov | mov #1 #2 | #+2]

[inc | inc #1 | #+1]    [dec | dec #1 | #+1]

[On | cmp #1 #3 | jn#2 M1> | #4>L | M1:]

[call | push #L>2 | call #1]

[move | push #2 | pop #1 | #+2]      ; (for mem to mem moves, for exemple)

[If | #=3 | cmp #1 #3 | jn#2 I1>]
[Else_if | #=3 | jmp I9> | I1: | cmp #1 #3 | jn#2 I1>]
[Else | Jmp I9> | I1:]
[End_if | I1: | I9:]

guga

#5
Hi JJ. Those are only the default macro set to make the true code more readable. The syntax in rosasm actually is much similar to Nasm, but with the macros it is easier to make it more human friendly. Here is the TITLE where it begins "TITLE WindowStart":

______________________________________________________________________________________________________________________

Main:

    call 'KERNEL32.GetModuleHandleA' &NULL | mov D$hInstance eax
    call 'comctl32.InitCommonControlsEx' INITCOMMONCONTROLSEX

    call InitInstance MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT
    If eax <> 0
        call 'USER32.ShowWindow' D$hMain, &SW_SHOW
        call 'User32.GetMessageA' MSG, &NULL, 0, 0
        While eax <> 0
            call 'User32.TranslateMessage' MSG
            call 'User32.DispatchMessageA' MSG
            call 'User32.GetMessageA' MSG, &NULL, 0, 0
        End_While
    End_If
    call 'GDI32.DeleteObject' D$Dib
    call 'GDI32.DeleteDC' D$hdc_dib
    call 'GDI32.DeleteObject' D$brush_bars
    call 'GDI32.DeleteObject' D$brush_winner

    call 'KERNEL32.ExitProcess' 0

______________________________________________________________________________________________________________________

[szAppName: B$ "ONNX Runtime Sample - MNIST", 0]

[wc:
 wc.cbSize: D$ len
 wc.style: D$ 0
 wc.lpfnWndProc: D$ WndProc
 wc.cbClsExtra: D$ 0
 wc.cbWndExtra: D$ 0
 wc.hInstance: D$ 0
 wc.hIcon: D$ 0
 wc.hCursor: D$ 0
 wc.hbrBackground: D$ (&COLOR_WINDOW + 1)
 wc.lpszMenuName: D$ 0
 wc.lpszClassName: D$ 0
 wc.hIconSm: D$ 0]


Proc InitInstance:
    Arguments @WindowWidth, @WindowHeight

    move D$wc.hInstance D$hInstance
    call 'USER32.LoadIconA' 0, &IDI_APPLICATION | mov D$wc.hIcon eax
    call 'USER32.LoadCursorA' 0, &IDC_ARROW | mov D$wc.hCursor eax
    move D$wc.lpszClassName szAppName
    call 'USER32.RegisterClassExA' wc
    On eax = 0, ExitP
    call CreateDibImageData
    call 'USER32.CreateWindowExA' 0, szAppName, szAppName, &WS_OVERLAPPEDWINDOW__&WS_CLIPCHILDREN,
                                  0, 0, D@WindowWidth, D@WindowHeight,
                                  &NULL, 0,
                                  D$hInstance, &NULL
    On eax = &FALSE, ExitP
    mov D$hMain eax


EndP

See ? No hard to follow the syntax and readable once we previously do the default macro set..


In RosAsm, there´s no hidden statement or macros (as in masm). Everything is done by the user. Except for a few statements to make the code be more easier to follow in the interface, such as TITLE which is used to split the code in different parts that are displayed in Tabs on the gui or the usage of "|" to allow code different opcodes or macros on the same line etc. All the rest is done by the user. I provided a default set of macros (which i always displays on the very 1st TITLE or the initial part of the source) to make it easier to read and follow the true code, but the user can choose either use it or create his own set.

It´s great to keep freedom for the user do whatever syntax or macros he wants without being forced to use hidden statements on the assembler (things such as "offset" in masm, or dword ptr, invoke, If - which is hidden by masm assembler etc etc, which are not asm instructions, but fixed and hidden  statements in masm assembler).

It has his pros and contras. Pros because allow the user to create almost everything he wants with whatever coding style he desires, without being forced to use hidden or fixed statements on the assembler. But contra, because in terms of RosAsm development itself, it may turn the internal development a true babel tower, because during the early years of development, different users contributed to the development, and sometimes each one has a different style and therefore different set of macros used internally in rosasm code to actually update rosasm, which lead to some difficulties to improve/update it.

And that´s what i´m currently doing. I´m updating the code in RosAsm itself to follow the default macro set and get rid of the extreme dependency of the interface. The code used to create RosAsm itself contains thousands of global variables that are reused everywhere, instead local variables to make it easier to maintain and follow, not to mention different coding styles in different parts of the development.


Another example of the dificulties i´m facing. In RosAsm, internally it has a function called WordEdge to identify the boundaries used to distinguish what is an equate, a variable etc etc. It is a very old code and extremely slow, that didn´t even used any "Proc / EndP" macro to make it readable or at least faster in terms of function alignment, such as:

_______________________________________________

[OneWordChars: B$ '0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.' 0
 OneWordCharsLen: D$ len
 Edge: B$ 0   OddWord: 0   BackAnyWhere: &TRUE]
____________________________________________
; WordEdge looks if a char is or not inside OneWordChars and tells if word edge or not.
; we preserve the flags because direction flag may be set on or off by caller:

WordEdge:
    pushfd | cld
        push ecx, esi, edi
            mov ecx D$OneWordCharsLen, edi OneWordChars, B$Edge &TRUE
            repne scasb | jne L9>
                mov B$Edge &FALSE
L9:     pop edi, esi, ecx
    popfd
ret

I updated it yesterday to make it work faster and yet more readable, simply using a table, such as:
; WordEdge looks if a char is or not inside OneWordChars and tells if word edge or not.
; No more need to flag preservation, since we didn´t changed any flag on the new code which eventually was set on or off by caller:

[WordEdgeTbl: D$ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
              D$ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,
              D$ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
              D$ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0,
              D$ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
              D$ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
              D$ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
              D$ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
              D$ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
              D$ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
              D$ 1, 1, 1, 1, 1, 1]

;;
    A complete review of wordedge fuunction. Now we use a table to find the chars related to a wordedge.
    Chars from "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ." are flagged as &FALSE (0)
    Otherwise, they are flagged as &TRUE (1).
    The table is simply a set of 256 dwords used as a index, where each dword represents the position/value of
    a byte (char in our case). So, if eax contains the letter 'A', we will look at the position (65 = 041 in hexa)
    since 65 is the value of char 'A' and so on.
;;
; 1st parameter - the input in eax. Didn´t used any "argument"  macro to define a parameter yet. Maybe later i´ll update it again
; once fix the other parts of the code that uses this function.

Proc WordEdge:
    Uses eax

    movzx eax al
    mov eax D$WordEdgeTbl+eax*4
    mov B$Edge al

EndP


See ? More readable and faster, and fewer instruuctions.  Only uses 3 lines of code, and of course the ones in the macro set ("uses" - for push/pop - preserve registers. In case preserving eax. push eax in the start and pop eax before the function exits) and the Proc/EndP macro which is the default push ebp | mov ebp esp, pop ebp ... ret... ) instructions.

Same thing with other internal function to display the equates. It is one called "ShowEquate" written as:

ShowEquate:
     mov ebx, eax

     mov edi ShowEquateHexa, esi TrashString ; <--- TrashString global variable used everywhere. Why doing like this ?????
     While B$esi <> 0
        movsb
     End_While
     mov eax '   =' | stosd | mov eax '    ' ecx 3 | rep stosd

     push edi, ebx
         std
            mov ecx 9
;L1:
            Do
                If ecx = 5
                    mov al '_' | stosb
                End_If
                If ecx = 1
                    mov al '_' | stosb
                End_If
                mov al bl | and al 0F | add al '0' |  On al > '9', add al 7
                stosb | shr ebx 4; | loop L1<
                dec ecx
            Loop_Until ecx = 0
         cld
     pop ebx, edi
     inc edi

     mov D$edi '_h  ', D$edi+4 '  [' | add edi 7

     mov eax ebx | call WriteEaxDecimal

     mov D$edi ']   ', B$edi+4 0

     call 'USER32.MessageBoxA' D$hwnd, ShowEquateHexa, ShowEquateTitle, &MB_SYSTEMMODAL
ret

Now...i reviewed it completely and it simply is rewritten as:
Proc ShowEquate:
    Arguments @hWndMain, @pEquateName, @EquateValue
    Structure @TmpString 128, @pStringStartDis 0 ; <--- Using structure macro to reserve enough space in the stack to hold the string to be displayed
    Uses ecx, edx, edi

    mov edi D@TmpString
    C_call FormatStr edi, {B$ "%s = 0x%xh (%d)", 0}, D@pEquateName, D@EquateValue, D@EquateValue ; <-- my clone of ws_printfA. Need to used it in a dll form (FastCRT.FormatStr) - To do later :)
    mov B$edi+eax 0
    call 'USER32.MessageBoxA' D@hWndMain, D@TmpString, {B$ 'Win Equate Value', 0}, &MB_SYSTEMMODAL

EndP
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com