А именно такое "методы повышения" будут в центре внимания вебинара "“Как с помощью инструментария разработчика сделать программный код эффективным”, подробнее о теме и зарегистрироваться – тут, который состоится в день "тройных чисел" – 12.12.12, но в 11:00.
К сожалению, по организационно-техническим причинам презентеры (слово хотя и новое, но мне видится оно лучше отражает суть дела, чем "спикеры") из Нижегородского исследовательского центра Intel – Галина Санжарлинская, Екатерина Антакова
[spoiler]
– не могут напрямую поучаствовать в наших блог-дискуссиях.
Но все же по почте им удалось прислать мне послание – они следят за нашими разговорами и обещают: "Все вопросы относительно технических возможностей повышения эффективности кода с помощью программных инструментов Intel, приведенные в комментариях, мы постараемся прокомментировать в ходе вебинара".
Что ж, это отрадно…
Мой тезис по теме остается прежним: эффективность кода должна быть оптимальной. А именно: уровень эффективности – некий компромисс между целовой бизнес-задачей и затратами на повышение эффективности.
Пример из уже довольно далекой программистcкой жизни.
В 1989-91 гг. в рамках собственной разработки прикладного ПО для IBM PC AТ на QuickBasic сделал набор библиотек для пользовательского интерфейса (окна, меню, и многое другое). Которые сначала использовал "для себя", а потом преобразовал в коммерческий продукт (Kolesov QB Tools – "Повоем на луну Basic-DOS".
Сначала все это работало в текстовом режиме экрана (поди, и не помнит никто, что это такое), но все же – графика. Кстати, вот запустил рекламную демо: работает!
Это то, что мы тогда видели на полном экрана монитора (14 дюймов, 80*25 символов). Немного посмотрел – самому дурно стало – сколько же кода тогда было написало! А ведь это – только капля от написанного тогда).
Так вот. Поначалу вся графика была написана на самом QB. По началу, все это вполне устраивало (а уж по сравнению с командной строкой, казалось просто фантастикой). Но когда привыкли к "оконным инновациям", скорость рисовки стала несколько утомлять. Не сказать, что это мешало работе пользователя (а поначалу это был я сам), но все же то, что процесс рисования был заметен – несколько раздражало.
Встал вопрос – как ускорить.
Средства Интел тут не помогли бы. По двум причинам: 1) было понятно, что простая оптимизация компилятору тут не поможет 2) никаких средств от Интела не было и в помине.
Нужны были меры организационно-алгоритмически-технологического характера.
1) Поменять язык (это и не помогло бы)
2) поменять алгоритмы (тоже не вариант – все уже было "вылизано")
3) делать что-то еще
Простой вариант – это использовать для рисовки функции BIOSа. В QB такие возможности были, что я и сделал.
Было получено отличное ускорение, скорость была "вполне" – глазом процесс рисовки стал не виден.
Но что-то там было все же не очень хорошо. Сейчас уже точно не помню, но кажется, выявились две проблемы
Через БИОС была доступны не все нужные для графики функции.
Возникли проблемы с совместимостью.
К тому времени моими программами пользовался уже не только я сам, и выяснилось, что на других ПК (сейчас не помню точно, но что-то было) все работало не всегда так, как хотелось бы.
Короче говоря, функции вывода графики были переписаны на Ассемблере. И на этом все закончилось – все стало работать еще быстрее (по сравнению с БИОС) и вполне устойчиво.
НО!
Объем кода на Ассемблере в начальном варианте QB Tools составлял не более 1-5% от общего кода. По мере расширения функционала эта доля быстро приближалась к нулю (как было 5-10 подпрограмм, так и осталась).
Трудоемкость написания на Ассемблере была раз в 10-100 больше чем на QB. Объем кода был небольшой, а повозиться пришлось. К тому же там нужно было вносить кое-какие расширения.
А дальше было вот что. В 1994 году я приобрел свой первые персональный ПК (НИИ не мог купить, его устраивали AT) – 486DX. Таких тогда мало в России еще было.
И выяснилось, что Ассемблеровский вариант графики (текстовой, по крайней мере) для 486DX не нужен. Я стал на свой ПК работать с QB-графикой (так было проще делать компоновку загрузочного модуля, все же смешанное программирование – это некоторые неудобства…). А клиентам продавал (да, уже пошли продажи!) вариант в ASM – они работали на AT и XT.
А через пару лет и им стал компоновать с QB – они тоже перешли на более мощные ПК.
Вот такая история о том, нужно бороть за эффективность код. Зачем и как…
========
P.S. Чтобы уж логично закончить мемуары, приведу тут два варианта процедур "сохранения-вывода фрагмента экрана на BAS и ASM
DECLARE SUB WNKstore (irow%, icol%, idr%, idc%, a$, kod%) DEFINT I-N '*********************************************************** '************ K o l e s o v Q B T o o l s ************** '* БИБЛИОТЕКА подпpогpамм QB_WNK v.2.87 * '* поддержка оконного интерфейса в текстовом режиме экрана * '*********************************************************** '* Модуль WNK_BAS.BAS * '* Процедуры работы с видеопамятью * '*---------------------------------------------------------* '* Альтернативный вариант модуля WNK_ASM.BAS * '* - вывод средствами BASIC * '*********************************************************** '========================================================== '====================== ВНИМАНИЕ: ====================== ' Процедура WNKstore использует обращение к подпрограммам, ' написанным на ассемблере: ' CopyScrBox - вариант для QuickBASIC v.4.0 ' CopyScrBox7 - вариант для BASIC v.7.0 ' Необходимо исправить непосредственно текст процедуры WNKstore ' для использования одной из этих подпрограмм. ' ' ============ СЕЙЧАС текст соответствует v.4.0 ================== ' ' При работе в среде QB необходимо создать ' двоичную библиотеку .LIB, .QLB ' (см. текст модуля WNKVIDEO.ASM) и загружать: ' ' QB.EXE /L WNKVIDEO '============================================================ ' СОСТАВ ПРОЦЕДУР МОДУЛЯ: ' WNKstore - сохранение/восстановление окна ' WNKshadow - вывод "тени" под окно ' WNKscreen0 - установка активной и видимой страницы ' ********************** ' Общие формальные параметры: ' --------------------------- ' irow, icol - координаты левого верхнего угла окна (строка, колонка) ' idr, jdl - размеры окна (строк, колонок) '------------------------------------------------------------------- ' сохранение/восстановление окна: ' Call WNKstore (irow, icol, idr, jdl, a$, kstore) ' - " - ' a$ - симв. переменная для хранения изображения окна (рабочий буфер) ' kstore = 0 - чтение "окна" (сохранение) ' = 1 - восстановление '------------------------------------------------------------------- ' вывод "тени" под окно: ' CALL WNKshadow(irow, icol, idr, jdl, Kft, Kbt) ' Kft,Kbt - цвета тени '------------------------------------------------------------------- ' определение активной и видимой странцы: ' CALL WNKscreen0 (Apage%, Vpage%) ' Apage%, Vpage% - номера активной и видимой странцы ' видеопамяти (0-7) '*********************************************************************** DIM SHARED Offset% END SUB WNKscreen0 (Apage%, Vpage%) ' ' Установка параметров режима SCREEN 0 ' (это нужно для установки адресов видеопамяти) ' Apage% - номер активной старницы ' Vpage% - номер видимой старницы '------------------------------------------------ SCREEN 0, , Apage%, Vpage% Offset% = 4096 * Apage% ' смещение видеопамяти END SUB SUB WNKshadow (irow, icol, idr, idc, Kft, Kbt) ' вывод "тени" под окно ' Kft,Kbt - цвета тени '''''''''''''''''''''''''''''''''''''''''''' ' код атрибутов цвета тени: Kct = (Kft AND 15) + (Kbt AND 7) * 16 ' -------------------------------------------------- ' вариант с модулем WNK_ASM.ASM: ' CALL ModifyAtr(irow + 1, icol + idc, idr, 2, Kct) ' CALL ModifyAtr(irow + idr, icol + 2, 1, idc - 2, Kct) ' -------------------------------------------------- ' вариант на QB: DEF SEG = &HB800 ik = irow * 160 + (icol + idc - 1) * 2 + 1 + Offset% FOR i = 1 TO idr: POKE ik, Kct: POKE ik + 2, Kct: ik = ik + 160: NEXT i ik = (irow + idr - 1) * 160 + (icol) * 2 + 3 + Offset% FOR i = 3 TO idc: POKE ik, Kct: ik = ik + 2: NEXT i DEF SEG END SUB SUB WNKstore (irow, icol, idr, idc, a$, kod) ' **** сохранение/восстановление картинки окна ' irow, icol - координаты левого верхнего угла окна (строка, колонка) '1) kod = 0 - чтение "окна" (сохранение) ' Вход: idr, idc - размеры окна (строк, колонок) ' Выход: a$ - симв. переменная для хранения изображения окна '2) Kod = 1 - восстановление ' Вход: a$ - симв. переменная для хранения изображения окна ' Выход: idr, idc - размеры окна (строк, колонок) '*********************************************************************** ' IF kod = 0 THEN ' сохранение окна a$ = CHR$(idr) + CHR$(idc) + SPACE$(idr * idc * 2) ELSE idr = ASC(a$): idc = ASC(MID$(a$, 2, 1)) END IF '----------------------------------------------------- ' вариант с модулем WNK_ASM.ASM: ' CALL CopyScrBox(SADD(a$)+2, irow, icol, idr, idc, kod) '----------------------------------------------------- ' вариант на QB: DEF SEG = &HB800 k = 3: ik0 = (irow - 1) * 160 + (icol - 1) * 2 + Offset% FOR i = 1 TO idr ik = ik0 FOR j = 1 TO idc IF kod = 0 THEN MID$(a$, k, 1) = CHR$(PEEK(ik)) MID$(a$, k + 1, 1) = CHR$(PEEK(ik + 1)) ELSE POKE ik, ASC(MID$(a$, k, 1)): POKE ik + 1, ASC(MID$(a$, k + 1, 1)) END IF k = k + 2: ik = ik + 2 NEXT j ik0 = ik0 + 160 NEXT i DEF SEG END SUB SUB WnkStorePage (Page$, kod) ' ' запоминание (Kod=0)/восстановление (=1) тек. активной страницы CALL WNKstore(1, 1, 25, 80, Page$, kod) END SUB ;********************************************************** ;************ K o l e s o v Q B T o o l s ************* ;* БИБЛИОТЕКА подпpогpамм QB_WNK v.2.87 * ;********************************************************** ;* Модуль WNKVIDEO.ASM * ;*--------------------------------------------------------* ;* Подпрограммы прямого обращения к видеопамяти в * ;* текстовом режиме экрана - SCREEN 0 * ;* для цветного монитора - CGA, EGA, VGA * ;********************************************************** ; Внешние процедуры: ; ------------------ ; CopyScrBox - чтение/запись фрагмента экрана в символьную ; переменную (переменная резервируется в вызывающей ; программе) - вариант QB v.4.0 ; CopyScrBox7 - - " - вариант QB v.7.0 ; ModifyAtr - изменение атрибутов цвета фрагмента экрана ; ; ActiveVideoPageSet0 - установка адреса активной видеостраницы ; ; ************************************************ ; Внутренние процедуры: ; --------------------- ; GetScrParam - обработка входных параметров ;*************************************************************** ; ОБРАЩЕНИЕ: ;--------------------------------------------------------------- ; CALL CopyScrBox(offset%, irow%, icol%, idr%, idc%, kod%) ; вариант QB v.4.5. ; kod = 0 - чтение фрагмента видеопамяти ; = 1 - восстановление - " - ; irow%, icol% - координаты левого верхнего угла ; (строка и столбец) ; idr%, idc% - размеры фрагмента (по вертикали и горизонтали) ; offset% = SADD(a$) - адрес символьной переменной (смещение) ; ------------------ ; CALL CopyScrBox7(Ssegadd&, irow%, icol%, idr%, idc%, kod%) ; вариант QB v.7.0. ; Ssegadd& = SSEGADD(a$) - адрес символьной переменной (полный) ;--------------------------------------------------------------- ; CALL ModifyAtr( irow%, icol%, idr%, idc%, atribut%) ; atribut% - новый атрибут (цвет символа) ;--------------------------------------------------------------- ; CALL ActiveVideoPageSet0(Apage%) - установка адреса активной видеостраницы ; Apage% - номер видеостаницы (0-7) ;*************************************************************** ; ПРИМЕРЫ ПРИМЕНЕНИЯ: ;*************************************************************** ; SCREEN 0 ' По умолчанию (после загрузки программы) ; ' - работа с 0-й видеостраницей ; ... ; 'запоминание фрагмента ; buffer$=SPACE$(idr%*idc%*2) ' резевируем переменную ; CALL CopyScrBox(SADD(buffer$),irow%,icol%,idr%,idc%,0) ; ... ; 'восстановление фрагмента ; CALL CopyScrBox(SADD(buffer$),irow%,icol%,idr%,idc%,1) ; ... ; ' изменение атрибутов цвета: ; ' Kfore, Kback - цвет символа и фона ; atribut%=(Kfore AND 15) + (Kback AND 7) * 16 ; if Kfore>15 then atribut%=atribut%+128 ; CALL ModifyAtr( irow%, icol%, idr%, idc%, atribut%) ; ' ; ' после переопределения активной видестраницы необходимой ; ' обратиться к процедуре ActiveVideoPageSet0, например: ; SCRREN 0, , 3, 2 ' 3 - активная видеостраница, 2 - видимая ; CALL ActiveVideoPageSet0(3) ; ... ; Создание библиотеки: ; ==================== ; MASM.EXE WNKVIDEO.ASM; ; LIB.EXE WNKVIDEO.LIB + WNKVIDEO.OBJ; ;4.5: ; LINK /Q WNKVIDEO.LIB,WNKVIDEO.QLB,,BQLB45.LIB; ;7.0: ; LINK /Q WNKVIDEO.LIB,OUTVIDEO.QLB,,QBXQLB.LIB; ; ; Для использования подпрограмм в среде QuickBASIC ; загрузите: ; QB.EXE /L WNKVIDEO.QLB ;******************************************************** .MODEL MEDIUM .DATA ; координаты фрагмента: нумерация с НУЛЯ ! idr db ? ; кол-во строк idc dw ? ; кол-во столбцов StrSeg dw ? ; адрес сегмента символьной строки (или откуда копируем - DS) Aoffset dw 0 ; смещение видеопамяти: по умолчанию 0-я страниница .CODE ; GetVideoSeg Proc ; определение сегмента видеопамяти mov ah,0Fh int 10h ;INT 10H fn. 0Fh - Get Video Mode mov ax,0B800h ;assume COLOR screen for now cmp al,07h ;is it MONOCHROME mode? jne arnd1 mov ax,0B000h ;yes, set for mono screen seg arnd1: mov es,ax ; адрес сегмента видеопамяти ret GetVideoSeg endp ; CopyScreenBox Proc near ; обмен c видеопямятью mov StrSeg,ax ; адрес сегмента символьной строки mov si,[di] ; смещение call GetVideoSeg ; определение адреса сегмента mov di,[bp]+6 ; получаем код операции mov dh,[di] mov dl,0 ; обнуляем - признак операции CopyScrBox call PutVideo ; перезапись в видео память ret CopyScreenBox endp ; перезапись в видеопамять PutVideo proc near ; определение координаты фрагмента mov di,[bp]+14 ; Irow mov al,[di] dec al mov bl,80 mul bl ; AX - адрес строки mov di,[bp]+12 ; Icol mov bx,[di] dec bx add ax,bx ; смещение в строке add ax,ax add al,dl ; смещения для вывода атрибутов add ax,Aoffset ; адрес видеостраницы ; ; установка счетчиков mov di,[bp]+10 ; idr - длина по вертикали mov cl,[di] mov idr,cl mov di,[bp]+8 ; idc - длина по горизонтали mov cx,[di] mov idc,cx xor bl,bl ; обнуление счетчика по вертикали ; сейчас: ; ax - смещение видеопамяти ; es - адрес сегмента видеопямяти (приемник) ; StrSeg - адрес сегмента строки (источник) ; si - смещение строки (источник) ; Для операции GetBox надо поменять адреса источника и приемника cmp dl,0 ; вывод атрибутов? jne next ; да, CopyAtr ; копирование экран - подготовка адресов ; ds:si (откуда) -> es:di (куда) cmp dh,0 ; 0 - Get jne next ; PutBox: строка -> экран, ничего не меняем ; Get: экран -> строка : все меняем местами mov di,si ; di - смещение в симв. строке mov cx,StrSeg ; адрес сегмента строки mov StrSeg,es ; адрес сегмента видеопамяти! mov es,cx ; копируем в строку! ; ; пересылка фрагмента next: ; вывод одной строки mov cx,idc ; длина строки экрана cmp dl,0 ; вывод атрибутов? je CopyBox ; нет, копирование экрана ; вывод строки атрибутов mov di,ax ; смещение видеопамяти в DI next_str: ; вывод очередного байта mov es:[di],dh ; да, DH - код атрибута add di,2 ; увеличиваем адрес видеопамяти loop next_str ;не последний символ в сроке? jmp GO_ALL ;переход к след. строке экрана ; ; пересылка строки CopyBox: cmp dh,0 ; 0 - считать je GetBox ; да PutBox: mov di,ax ; <>0 - восстановить: строка -> экран jmp GO_BOX GetBox: mov si,ax ; экран строка GO_BOX: push ds mov ds,strseg ; адрес сегмента источника rep movsw pop ds ; восстановить DS ; ; обработка след. строки GO_ALL: add ax,160 ; адрес следующей строки inc bl cmp bl,idr ; последняя строка? jne next ; нет ; ret PutVideo endp ; public CopyScrBox ; обмен с видео пямятью - v.4.5. CopyScrBox proc push bp mov bp,sp mov di,[bp]+16 ; адрес симв. переменной mov ax,ds ; адрес сегмента данных call CopyScreenBox ; обмен данными pop bp ret 12 CopyScrBox endp ; public CopyScrBox7 ; обмен с видео пямятью - v.7.0. CopyScrBox7 proc push bp mov bp,sp mov di,[bp]+16 ; адрес симв. переменной mov ax,[di+2] ; адрес сегмента данных call CopyScreenBox ; обмен данными pop bp ret 12 CopyScrBox7 endp ; ; public ModifyAtr ; программа изменения атрибутов ModifyAtr proc push bp mov bp,sp call GetVideoSeg ; определение адреса сегмента mov di,[bp]+6 ; получаем код атрибута mov dh,[di] mov dl,1 ; 1 - признак операции ModifyAtr call PutVideo ; перезапись в видео память pop bp ret 10 ModifyAtr endp ; public ActiveVideoPageSet0 ActiveVideoPageSet0 proc ; определение активной видеостраницы push bp mov bp,sp mov di,[bp]+6 mov bx,[di] ; номер видеостраницы mov ax,4096 mul bx mov Aoffset,ax pop bp ret 2 ActiveVideoPageSet0 endp end |
Фото:
Андрей, сорри, я сожалею о том, что влез сюда с комментариями, и больше в беседе не участвую. Тема никого, кроме нас с тобой, не интересует. Пока )
Первоочереденая, обязательная - написать работающий код
Вторая, по мере необходимости, - повысить его эффективность.
Если ты прочитаешь пост, написанный в начале этой ветки, то увидишь, что приведенный мной пример разработки 20летней давности как раз иллюстрирует ровно этот подход.
А после этого посмотри на заголовок поста: так как раз задает вопрос - "нужно ли бороться за повышение эффективности кода?" Точнее так: до каких пределов нужно бороться и какими методами.
А теперь посмотри (там же - в посте) - по поводу чего написан этот пост. Он написан по поводу того, что завтра (да, уже завтра, через 11 часов и 35 минут) состоится вебинар, в котором главными действующими лицами будут две замечательные сотрудницы Нижегородского исследовательского центра Интел. И посмотри название их доклада.
Они как раз исходят из базового тезиса - "повышать эффективность НУЖНО". А я их хочу как раз спросить - "нужно ли?"
Как ты уже, наверное, понял, мы в этом вопросе - союзники, а не противники, как тебе показалось.
Короче говоря: подключайся завтра (уже через 11 часов 22 минуты) к вебинару и давай вместе поспрашиваем барышень о том, как нужно вести разработку ПО.
Что касается "никто, кроме нас с тобой не интересует", то тут ты, думаю, ошибаешься. Я точно знаю еще одного, который пишет мне комментарии в письмах. Трое - это уже достаточно для многих серьезных дел