Буфер для текста.

Тема в разделе "WASM.WIN32", создана пользователем Valentin, 1 фев 2009.

  1. Valentin

    Valentin Member

    Публикаций:
    0
    Регистрация:
    2 ноя 2007
    Сообщения:
    130
    leo

    Кстати у меня скорость обработки инфы в сотни раз быстрее, чем подобные в моей области сделаны на Васиках.
     
  2. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Valentin
    Дело не столько в самом Васике или асме, сколько в неверном (бездумном) использовании стандартных средств языка. Если для твоей задачи бесхитростно юзать склейку динамических строк в виде S=S+S1, то тормоза будут по любому - и в васике, и в дельфях и С++, т.к. при достаточно большой длине S будут возникать перераспределения памяти под S с копированием больших объемов данных из одного блока памяти в другой - а тут тебе и тормоза чтения\записи из-за невлезания данных в кэш процессора и отказы страниц и т.п., и все это может повторяться десятки-сотни раз. А если сразу выделить под результирующую строку блок памяти достаточно большого размера, то ничего этого не будет и скорость склейки будет значительно выше - и в си, и в дельфях, и в васике (если юзать функции АПИ CopyMemory и т.п.)
     
  3. Valentin

    Valentin Member

    Публикаций:
    0
    Регистрация:
    2 ноя 2007
    Сообщения:
    130
    leo

    Согласен. Я заметил ч-з прогрессбар что с накоплением строки работа идет все медленнее и медленее, понятно.
    А как указать на конец буфера?? Если Вы опытный в памяти, приведите пожалуqста пример накопления строки в памяти.
    В ссылках на Ваши посты есть примеры, но архивы 7z не открываюся/
     
  4. int2e

    int2e New Member

    Публикаций:
    0
    Регистрация:
    9 янв 2009
    Сообщения:
    169
    Valentin
    1. Разово выделяешь 10-мегабайтовй буффер через VirtualAlloc
    2. Указатель сохраняешь в 2 переменные: указатель на буффер и в указатель на конец строки
    3. Делаешь самописную MylstrcpyA, которая после копирования, будет возвращать указатель на конец строки
    4. Формируешь строку

    Думаю, это будет самый быстрый вариант


    Пример
    Код (Text):
    1. /*---------------------------copy string-------------------------------------
    2. char* MylstrcpyA(char* dest, char* src)
    3. {
    4. char* pointer;
    5. _asm {
    6.          mov esi, [src]
    7.          mov edi, [dest]
    8.        copy_string:
    9.          movsb
    10.          cmp byte ptr [esi], 0
    11.          jnz   copy_string
    12.          mov byte ptr [edi], 0
    13.          mov [pointer], edi
    14.         }
    15.  return pointer;
    16. }
    Код (Text):
    1. /*---------------------------allocate memory-------------------------------------
    2. buff = VirtualAlloc(0, 0A00000h, MEM_COMMIT, PAGE_READWRITE); //buffer
    3. eos = (PCHAR)buff; //end of string
    4.  
    5. /*---------------------------sample----------------------------------------------
    6. eos = MylstrcpyA(eos, S1);
    7. eos = MylstrcpyA(eos, S2);
    8. eos = MylstrcpyA(eos, S3);
    9. eos = MylstrcpyA(eos, Sn);
    Дальше уже идет железная оптимизация, например замена опкодов на более быстрые, спаривающиеся, и.д. и.т.п.
    Я этих тонкостей не знаю, в этом поможет leo


    PS: если вдруг нужно онулить всю 10-мегабайтную строку, то делаешь так:
    Код (Text):
    1. eos    = (char*)buff;
    2. eos[0] = 0;
     
  5. MSoft

    MSoft New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2006
    Сообщения:
    2.854
    в этом случае строка не будет завершена 0
    считаю необходимым сделать как минимум mov byte ptr [edi],0 после цикла - мало ли как строка еще будет использоваться
     
  6. int2e

    int2e New Member

    Публикаций:
    0
    Регистрация:
    9 янв 2009
    Сообщения:
    169
    поправлено
     
  7. Valentin

    Valentin Member

    Публикаций:
    0
    Регистрация:
    2 ноя 2007
    Сообщения:
    130
    int2e

    Я работаю на МАSM32, нужен перевод:
    пока так:
    ; ---------------------------copy string-------------------------------------
    MylstrcpyA proc dest:lol: WORD, src:lol: WORD)

    LOCAL pointer:lol: WORD

    mov esi, [src]
    mov edi, [dest]
    copy_string:
    movsb
    cmp byte ptr [esi], 0
    jnz copy_string
    mov byte ptr [edi], 0
    mov [pointer], edi
    ret
    MylstrcpyA endp

    Теперь с памятью:
    ;---------------------------allocate memory-------------------------------------
    buff dd ?
    eos dd ?

    invoke VirtualAlloc,0, 0A00000h, MEM_COMMIT, PAGE_READWRITE
    mov buff,eax


    = (PCHAR)buff; //end of string ========= как здесь???

    ;---------------------------sample----------------------------------------------
    invoke MylstrcpyA, addr eos, addr S1
     
  8. int2e

    int2e New Member

    Публикаций:
    0
    Регистрация:
    9 янв 2009
    Сообщения:
    169
    Код (Text):
    1. MylstrcpyA proc  dest:DWORD, src:DWORD
    2.          mov esi, [src]
    3.          mov edi, [dest]
    4.        copy_string:
    5.          movsb
    6.          cmp byte ptr [esi], 0
    7.          jnz   copy_string
    8.          mov byte ptr [edi], 0
    9.          mov eax, edi
    10.          ret
    11. MylstrcpyA endp
    Код (Text):
    1. buff dd ?
    2. eos dd ?
    3.  
    4. invoke VirtualAlloc,0, 0A00000h, MEM_COMMIT, PAGE_READWRITE
    5. mov [buff],eax
    6. mov [eos], eax
    Код (Text):
    1. invoke MylstrcpyA, dword ptr [eos], addr S1
    2. mov [eos], eax
    3. invoke MylstrcpyA, dword ptr [eos], addr S2
    4. mov [eos], eax
    5. ;...
    6. invoke MylstrcpyA, dword ptr [eos], addr Sn
    7. mov [eos], eax
     
  9. Valentin

    Valentin Member

    Публикаций:
    0
    Регистрация:
    2 ноя 2007
    Сообщения:
    130
    int2e

    Понял, большое спасибо, я почти до этого и дошел в отладчике.
     
  10. Valentin

    Valentin Member

    Публикаций:
    0
    Регистрация:
    2 ноя 2007
    Сообщения:
    130
    int2e


    Код (Text):
    1.        copy_string:
    2.          movsb
    3.          cmp byte ptr [esi], 0
    4.          jnz   copy_string
    5.          mov byte ptr [edi], 0
    6.    ;      mov eax, edi - так не получается, строка уже в eax
    7.          ret
    теперь после выполнения:
    Код (Text):
    1. invoke MylstrcpyA, dword ptr [eos], addr S1
    2. mov [eos], eax
    в [eos] -строки нет.


    И еще, где учавствует buff -?
     
  11. int2e

    int2e New Member

    Публикаций:
    0
    Регистрация:
    9 янв 2009
    Сообщения:
    169
    По стандарту, функции возвращают значение в еах.

    Там строки и не будет. Там будет указатель на нее

    Если тебе понадобится освободить память либо занулить массив, то тут пригодится buff
     
  12. Valentin

    Valentin Member

    Публикаций:
    0
    Регистрация:
    2 ноя 2007
    Сообщения:
    130
    int2e

    А как же теперь достать собранную строку?
     
  13. Valentin

    Valentin Member

    Публикаций:
    0
    Регистрация:
    2 ноя 2007
    Сообщения:
    130
    int2e

    Все получилось, собранная строка лежит в buff.
    Еще раз огромное спасибо.
     
  14. Valentin

    Valentin Member

    Публикаций:
    0
    Регистрация:
    2 ноя 2007
    Сообщения:
    130
    А как реализовать функцию, которая будет накапливать строки в динамически увеличиваемом буфере
    Есть код, но он почему-то не работает:
    =========================================
    Код (Text):
    1. .686
    2. .model flat, stdcall
    3. option casemap:none
    4. include \masm32\include\kernel32.inc
    5. include \masm32\include\windows.inc
    6. include         \masm32\include\user32.inc
    7. includelib \masm32\lib\kernel32.lib
    8. includelib      \masm32\lib\user32.lib
    9. Mylstrcpy PROTO : WORD, :WORD
    10. .data
    11. STROKA db "HELLO", 0  ; Исходная строка
    12. .data?
    13. buffS dd ?  ; Указатель на буфер
    14. eos dd ?    ; Указатель на конец строки в буфере
    15. .code
    16. start:
    17.     ; Инициализация buffS с помощью VirtualAlloc
    18.     invoke VirtualAlloc, NULL, 1, MEM_COMMIT, PAGE_READWRITE
    19.     mov [buffS], eax
    20.     mov [eos], eax    ; eos указывает на начало buffS
    21.     ; Добавляем строку "HELLO"
    22.     invoke Mylstrcpy, dword ptr [eos], addr STROKA
    23.     ; Теперь buffS содержит "HELLO"
    24.     ; eos указывает на конец строки
    25.     ; Добавляем ещё одну строку
    26.     invoke Mylstrcpy, dword ptr [eos], addr STROKA
    27.     ; Теперь buffS содержит "HELLOHELLO"
    28.     ; eos указывает на конец строки
    29. ;   invoke MessageBox, NULL, buffS, NULL, MB_OK OR MB_ICONWARNING OR MB_SYSTEMMODAL
    30.     ; Освобождаем память
    31.     invoke VirtualFree, [buffS], 0, MEM_RELEASE
    32.    invoke MessageBox, NULL,  [buffS], NULL, MB_OK OR MB_ICONWARNING OR MB_SYSTEMMODAL
    33.     ; Завершение программы
    34.     invoke ExitProcess, 0
    35. Mylstrcpy proc public uses esi edi ebx dest:lol: WORD, src:lol: WORD
    36.     ; dest — указатель на конец строки в buffS
    37.     ; src — указатель на новую строку
    38.     ; Загружаем указатели
    39.     mov esi, src  ; esi = адрес новой строки
    40.     mov edi, dest ; edi = текущий конец строки в buffS
    41.     ; Находим длину новой строки (src)
    42.     xor ecx, ecx  ; Счётчик длины
    43.     mov ebx, esi  ; Сохраняем начало src
    44. find_src_len:
    45.     cmp byte ptr [ebx], 0  ; Проверяем конец строки
    46.     je  src_len_found
    47.     inc ecx                ; Увеличиваем счётчик
    48.     inc ebx                ; Переходим к следующему символу
    49.     jmp find_src_len
    50. src_len_found:
    51.     ; Находим текущую длину buffS
    52.     mov ebx, [buffS]  ; ebx = начало buffS
    53.     mov edx, edi      ; edx = текущий конец строки
    54.     sub edx, ebx      ; edx = длина текущей строки в buffS
    55.     ; Вычисляем новый размер буфера
    56.     add edx, ecx      ; edx = текущая длина + длина новой строки
    57.     inc edx           ; Учитываем нулевой символ
    58.     ; Выделяем новую память с помощью VirtualAlloc
    59.     invoke VirtualAlloc, NULL, edx, MEM_COMMIT, PAGE_READWRITE
    60.     test eax, eax     ; Проверяем, удалось ли выделить память
    61.     jz  fail          ; Если нет, завершаем с ошибкой
    62.     ; Копируем данные из старого буфера в новый
    63.     mov ecx, edi      ; ecx = текущий конец строки
    64.     sub ecx, [buffS]  ; ecx = длина текущей строки
    65.     mov esi, [buffS]  ; esi = начало старого буфера
    66.     mov edi, eax      ; edi = начало нового буфера
    67.     rep movsb         ; Копируем данные
    68.     ; Освобождаем старый буфер
    69.   mov  dword ptr [buffS],0
    70. ;   invoke VirtualFree, [buffS], 0, MEM_RELEASE
    71.     ; Обновляем указатель на буфер
    72.     mov [buffS], eax
    73.     invoke MessageBox, NULL, [eax], NULL, MB_OK OR MB_ICONWARNING OR MB_SYSTEMMODAL
    74.     ; Копируем новую строку в конец buffS
    75.     mov edi, eax      ; edi = новый адрес buffS
    76.     add edi, edx      ; edi = конец текущей строки
    77.     dec edi           ; Убираем нулевой символ
    78. copy_loop:
    79.     movsb             ; Копируем байт из [esi] в [edi]
    80.    cmp byte ptr [esi], 0  ; Проверяем конец строки
    81.     jne copy_loop
    82.     ; Добавляем нулевой символ в конец
    83.     mov byte ptr [edi], 0
    84.     ; Обновляем eos
    85.     mov [eos], edi
    86. fail:
    87.     ret
    88. Mylstrcpy endp
    89. end start
     
    Последнее редактирование: 22 фев 2025 в 20:47
  15. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.788
    Valentin

    Для начала нужно тэг кода применить, что бы как то прочитать :wacko:
     
  16. MaKsIm

    MaKsIm Active Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    149
    VirtualAlloc для кусочков произвольного размера лучше не использовать. Попробуйте написать через GetProcessHeap/HeapAlloc/HeapReAlloc
    VirtualAlloc надо использовать для работы с блоками кратными 4096 и выравненными на такие же адреса.
    Если нужен накопитель для строк, тогда достаточно простой функции копирования, которая возвращает количество скопированных символов.

    Код (ASM):
    1. ; fasm1 без макросов, i386, частичный кусок
    2. struc _buf_data { label .
    3.   .ptr    dd ?
    4.   .end    dd ?
    5.   .handle dd ?
    6. }
    7. ; блок данных
    8. buffer    _buf_data
    9.  
    10. str_hello db "HELLO", 0
    11.  
    12. ; секция кода
    13. ; ...
    14.         lea     ebx, [buffer]
    15.         call    _buf_init
    16.         lea     esi, [str_hello]
    17.         call    _strpush
    18.         call    _buf_free
    19. ; ...
    20.  
    21. _buf_init: ; in { ebx = указатель на переменную, которая содержит указатель на буфер для накопления в структуре из трех полей (не инициализированный) }, out { eax = указатель на буфер }
    22.   .init_size = 65536 ; 64 Кб начальный размер буфера
    23.   virtual at ebx
    24.     .buf _buf_data
    25.   end virtual
    26.         call    [GetProcessHeap]
    27.         push    .init_size
    28.         push    HEAP_ZERO_MEMORY
    29.         push    eax
    30.         call    [HeapAlloc]
    31.         lea     ecx, [eax + .init_size]
    32.         mov     [.buf.handle], eax
    33.         mov     [.buf.end], ecx
    34.         mov     [.buf.ptr], eax
    35.         retn
    36.  
    37.  
    38.  
    39. _buf_free: ; in { ebx = указатель на переменную, которая содержит указатель на буфер для накопления в структуре из трех полей (инициализированный) }
    40.   virtual at ebx
    41.     .buf _buf_data
    42.   end virtual
    43.         call    [GetProcessHeap]
    44.         push    dword [.buf.handle]
    45.         push    HEAP_ZERO_MEMORY
    46.         push    eax
    47.         call    [HeapFree]
    48.         xor     eax, eax
    49.         mov     [.buf.handle], eax
    50.         mov     [.buf.end], ecx
    51.         mov     [.buf.ptr], eax
    52.         retn
    53.  
    54.  
    55. _strcopy: ; in { esi = исходная строка; edi = буфер для копирования; ecx = указатель на конец буфера (по достижении этого значения edi будет ошибка нехватки памяти) }, out { eax = количество байт без учета 0; cf = признак ошибки }
    56.         pushfd
    57.         push    esi
    58.         mov     edx, edi
    59.         cld
    60.         jmp     _strcopy_start
    61. _stdcopy_loop:
    62.         cmp     edi, ecx
    63.         jae     _strcopy_out_of_memory
    64.         movsb
    65. _strcopy_start:
    66.         cmp byte [esi], 0
    67.         jnz _stdcopy_loop
    68.         mov     eax, edi
    69.         movsb
    70.         sub     eax, edx
    71.         pop     esi
    72.         popfd
    73.         cld
    74.         retn
    75. _strcopy_out_of_memory:
    76.         mov     edi, edx
    77.         xor     eax, eax
    78.         pop     esi
    79.         popfd
    80.         std
    81.         retn
    82.  
    83.  
    84.  
    85. _strpush: ; in { esi = исходная строка; ebx = указатель на переменную, которая содержит указатель на буфер для накопления в структуре из трех полей }, out { eax = количество байт }
    86.   virtual at ebx
    87.     .buf _buf_data
    88.   end virtual
    89.         push    edi
    90. _strpush_retry:
    91.         mov     edi, [.buf.ptr]
    92.         mov     ecx, [.buf.end]
    93.         call    _strcopy
    94.         jnc     _strpush_done
    95.         call    [GetProcessHeap]
    96.         mov     edx, [.buf.handle]
    97.         mov     edi, [.buf.end]
    98.         sub      edi, edx
    99.         add     edi, 4096
    100.         push    edi
    101.         push    edx
    102.         push    HEAP_REALLOC_IN_PLACE_ONLY
    103.         push    eax
    104.         call    [HeapReAlloc]
    105.         add     edi, [.buf.handle]
    106.         mov     [.buf.end], edi
    107.         jmp     _strpush_retry
    108. _strpush_done:
    109.         inc     eax
    110.         add     [.buf.ptr], eax
    111.         pop     edi
    112.         retn
     
    Последнее редактирование: 22 фев 2025 в 21:53
  17. Valentin

    Valentin Member

    Публикаций:
    0
    Регистрация:
    2 ноя 2007
    Сообщения:
    130
    MaKsIm, понял, спасибо, будем пробовать.
     
  18. alex_dz

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    523
    Кроме стандартного размера страницы 4096 байт (4 КБ), в некоторых архитектурах Windows также поддерживаются большие страницы размером 2 МБ и 1 ГБ.