OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Четверг, 17 Январь, 2019 11:37

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 54 ]  На страницу 1, 2, 3  След.
Автор Сообщение
 Заголовок сообщения: Абстракция Files.File и её реализации
СообщениеДобавлено: Воскресенье, 13 Январь, 2013 20:52 
Модератор
Аватара пользователя

Зарегистрирован: Среда, 16 Ноябрь, 2005 00:53
Сообщения: 4488
Откуда: Россия, Орёл
Иван Денисов в viewtopic.php?p=77096#p77096 писал(а):
Пожалуйста, поделитесь опытом, как это делать? Вопрос насущный. Даже для маленьких временных файлов создаваемых через Files.dir.New(), как я понял, идет обращение к диску. А очень бы хотелось, как вы говорите "над памятью".
Никакого секрета тут нет: как реализуете абстракцию, так "она" и будет работать.

1) Ограниченная реализация файлов в памяти, насколько помню, есть в подсистеме Dbu (http://www.zinnamturm.eu/downloadsDH.htm#Dbu)
2) Простейший пример: http://oberoncore.ru/library/temir_srav ... _ble_kboks
Код:
MODULE PrivFixedMemFiles;
(*
File
Reader
Writer
*)
  IMPORT Files;
 
  TYPE
    File* = POINTER TO RECORD (Files.File)
      len-: INTEGER;
      data-: ARRAY 4096 OF BYTE
    END;

    Reader* = POINTER TO RECORD (Files.Reader)
      base: File;
      pos: INTEGER
    END;
   
    Writer* = POINTER TO RECORD (Files.Writer)
      base: File;
      pos: INTEGER
    END;


  (* File *)

  PROCEDURE (f: File) Close*;
  BEGIN
    HALT(100)
  END Close;
 
  PROCEDURE (f: File) Flush*;
  BEGIN
    HALT(100)
  END Flush;

  PROCEDURE (f: File) Length* (): INTEGER;
  BEGIN
    RETURN f.len
  END Length;

  PROCEDURE (f: File) NewReader* (old: Files.Reader): Files.Reader;
    VAR  res: Reader;
  BEGIN
    IF (old # NIL) & (old IS Reader) THEN res := old(Reader) ELSE NEW(res) END;
    IF res.base # f THEN
      res.base := f; res.SetPos(0)
    END;
    res.eof := FALSE;
    RETURN res
  END NewReader;

  PROCEDURE (f: File) NewWriter* (old: Files.Writer): Files.Writer;
    VAR  res: Writer;
  BEGIN
    IF (old # NIL) & (old IS Writer) THEN res := old(Writer) ELSE NEW(res) END;
    IF res.base # f THEN
      res.base := f; res.SetPos(f.len)
    END;
    RETURN res
  END NewWriter;
   
  PROCEDURE (f: File) Register* (name: Files.Name; type: Files.Type; ask: BOOLEAN; OUT res: INTEGER);
  BEGIN
    HALT(100)
  END Register;


  (* Reader *)

  PROCEDURE (r: Reader) Base* (): Files.File;
  BEGIN
    RETURN r.base
  END Base;
 
  PROCEDURE (r: Reader) Pos* (): INTEGER;
  BEGIN
    RETURN r.pos
  END Pos;

  PROCEDURE (r: Reader) SetPos* (pos: INTEGER);
  BEGIN
    ASSERT(0 <= pos, 20); ASSERT(pos <= r.base.len, 21);
    r.pos := pos;
    r.eof := FALSE
  END SetPos;

  PROCEDURE (r: Reader) ReadByte* (OUT x: BYTE);
    VAR  f: File;
  BEGIN
    f := r.base;
    IF r.pos < f.len THEN
      x := f.data[r.pos];
      INC(r.pos);
      r.eof := FALSE
    ELSE
      x := 0;
      r.eof := TRUE
    END
  END ReadByte;

  PROCEDURE (r: Reader) ReadBytes* (VAR x: ARRAY OF BYTE; beg, len: INTEGER);
    VAR  f: File; i, j: INTEGER;
  BEGIN
    ASSERT(0 <= beg, 20); ASSERT(0 <= len, 21); ASSERT(beg + len <= LEN(x), 22);
    f := r.base;
    i := beg; j := r.pos;
    WHILE (j < f.len) & (len > 0) DO
      x[i] := f.data[j];
      INC(i); INC(j);
      DEC(len)
    END;
    r.eof := len > 0;
    r.pos := j
  END ReadBytes;


  (* Writer *)

  PROCEDURE (w: Writer) Base* (): Files.File;
  BEGIN
    RETURN w.base
  END Base;
 
  PROCEDURE (w: Writer) Pos* (): INTEGER;
  BEGIN
    RETURN w.pos
  END Pos;

  PROCEDURE (w: Writer) SetPos* (pos: INTEGER);
  BEGIN
    ASSERT(0 <= pos, 20); ASSERT(pos <= w.base.len, 21);
    w.pos := pos;
  END SetPos;

  PROCEDURE (w: Writer) WriteByte* (x: BYTE);
    VAR  f: File;
  BEGIN
    f := w.base;
    ASSERT(f.len + 1 <= LEN(f.data), 100);
    f.data[w.pos] := x;
    INC(w.pos);
    IF w.pos > f.len THEN f.len := w.pos END
  END WriteByte;

  PROCEDURE (w: Writer) WriteBytes* (IN x: ARRAY OF BYTE; beg, len: INTEGER);
    VAR  f: File; i: INTEGER;
  BEGIN
    ASSERT(0 <= beg, 20); ASSERT(0 <= len, 21); ASSERT(beg + len <= LEN(x), 22);
    f := w.base;
    ASSERT(f.len + len <= LEN(f.data), 100);
    i := beg;
    WHILE len > 0 DO
      f.data[w.pos] := x[i];
      INC(w.pos); INC(i);
      DEC(len)
    END;
    IF w.pos > f.len THEN f.len := w.pos END
  END WriteBytes;


  (* Программный интерфейс *)

  PROCEDURE New* (): File;
    VAR  res: File;
  BEGIN
    NEW(res);
    res.len := 0;
    RETURN res
  END New;

END PrivFixedMemFiles.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 13 Январь, 2013 22:13 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2546
Откуда: Россия, Ярославль
По поводу строк - всё равно придётся юзать NEW (хотя бы для каждого нового куска буфера), или ограничивать себя конкретной длиной строки.

А по поводу файлов - было бы интересно описать в этом треде механизм взаимодействия двух ББ через совместные области памяти, кажется, Илья Ермаков как-то раз упоминал о таком приёме, насколько я понимаю, там тоже использовались файловые абстракции.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 13 Январь, 2013 23:25 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9072
Откуда: Россия, Орёл
Во-первых, можно брать память из кучи ОС, во-вторых, можно делать NEW страницами фиксированного размера и просто кэшировать эти страницы глобально в модуле-реализации. Т.е. освободившиеся внутри одного объекта-буфера страницы сохранять в списке свободных, для повторного использования, не соря.

Ну а для общения двух ББ нужно использовать свою работу с логическими страницами внутри некоторого куска памяти, который отображен между ББ (через memory mapping), определить untagged-структуры для такого файла в памяти, чтобы объект Files.File был просто обёрткой над ними.

Я бы повыкладывал конкретный код, не жалко, если бы он не был сильно завязан на свои библиотеки - да и "постарел" код за 4 года, сейчас уже есть намерения переделать с высоты сегодняшнего понимания :)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 13 Январь, 2013 23:36 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9072
Откуда: Россия, Орёл
Иван Денисов в viewtopic.php?p=77096#p77096 писал(а):
Пожалуйста, поделитесь опытом, как это делать? Вопрос насущный. Даже для маленьких временных файлов создаваемых через Files.dir.New(), как я понял, идет обращение к диску. А очень бы хотелось, как вы говорите "над памятью".


Кстати, HostFiles неплохо кэширует в памяти (не говоря про ОС). Так что для прикладных задач нет ничего страшного в том, чтобы использовать Files.dir.New() или Files.dir.Temp().
Т.е. если какая-то настольная программа что-то получает/передаёт из сети, ей нужны буферы, то это вполне подходит (для настольной-то программы).
Я сам это использую, если тянуть зависимости от своего хозяйства нельзя (например, в учебных примерах).


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 13 Январь, 2013 23:48 
Администратор

Зарегистрирован: Вторник, 15 Ноябрь, 2005 01:14
Сообщения: 4199
Откуда: Россия, Орёл
Илья Ермаков писал(а):
Кстати, HostFiles неплохо кэширует в памяти (не говоря про ОС). Так что для прикладных задач нет ничего страшного в том, чтобы использовать Files.dir.New() или Files.dir.Temp().

Для последнего, как показывает вскрытие, даже запись на диск не происходит при сносных объёмах. Так что как буфер катит.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 14 Январь, 2013 00:14 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2546
Откуда: Россия, Ярославль
Илья Ермаков писал(а):
Я бы повыкладывал конкретный код, не жалко, если бы он не был сильно завязан на свои библиотеки - да и "постарел" код за 4 года, сейчас уже есть намерения переделать с высоты сегодняшнего понимания :)
Ну да, интереснее сразу про реализацию говорить, потому что в принципе механизм ясен.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 14 Январь, 2013 15:36 
Аватара пользователя

Зарегистрирован: Четверг, 08 Октябрь, 2009 15:00
Сообщения: 2247
Илья Ермаков писал(а):
Кстати, HostFiles неплохо кэширует в памяти (не говоря про ОС). Так что для прикладных задач нет ничего страшного в том, чтобы использовать Files.dir.New() или Files.dir.Temp().

Т.е. если какая-то настольная программа что-то получает/передаёт из сети, ей нужны буферы, то это вполне подходит (для настольной-то программы).
Я сам это использую, если тянуть зависимости от своего хозяйства нельзя (например, в учебных примерах).
Спасибо за эту информацию! Поскольку так и сделал для приема файлов по HTTP и переживал, что при этом диск используется. Теперь чаще буду пользоваться этим приемом значит :) И длинные строки безразмерные тоже значит можно через Files делать? Такое часто надо для биоинформатики, например, где строки очень большие. И для приема данных с прибора...

А можно ли в HostFiles менять параметры:
Код:
nofbufs = 4;   (* max number of buffers per file *)
bufsize = 2 * 1024;   (* size of each buffer *)

? Кто пробовал?

Оперативной памяти ведь теперь на компах много, а вот обращение к жесткому диску хотелось бы пореже совершать, при использовании Files.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 14 Январь, 2013 17:20 
Администратор

Зарегистрирован: Вторник, 15 Ноябрь, 2005 01:14
Сообщения: 4199
Откуда: Россия, Орёл
Илья Ермаков писал(а):
Т.е. если какая-то настольная программа что-то получает/передаёт из сети, ей нужны буферы, то это вполне подходит (для настольной-то программы).

От задачи идти надо. Бывает, что и «серверная программа» настолько тихо работает, что может файлы использовать спокойно. А бывает, что и «настольная» обрабатывает гигабайты...


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 14 Январь, 2013 18:16 
Модератор
Аватара пользователя

Зарегистрирован: Среда, 16 Ноябрь, 2005 00:53
Сообщения: 4488
Откуда: Россия, Орёл
Иван Денисов писал(а):
А можно ли в HostFiles менять параметры:
Код:
nofbufs = 4;   (* max number of buffers per file *)
bufsize = 2 * 1024;   (* size of each buffer *)

? Кто пробовал?

Оперативной памяти ведь теперь на компах много, а вот обращение к жесткому диску хотелось бы пореже совершать, при использовании Files.
Эти цифры долежали тут с оригинальной системы Оберон... Вопрос же не в том --- можно ли, а в точном описании эффекта...
Иван Денисов писал(а):
И длинные строки безразмерные тоже значит можно через Files делать? Такое часто надо для биоинформатики, например, где строки очень большие. И для приема данных с прибора...
... и когда дело идёт о конкретной специфической задаче рекомендовал бы уповать не на готовые библиотеки, а на свою голову. Так и так её напрягать: либо разбираясь со спецификой реализации и допиливая её, либо изучая соотв. алгоритмы и структуры данных (и т.п.) для собственной, ориентированной на задачу, реализации. Последнее полезнее.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 14 Январь, 2013 20:14 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 7946
Откуда: Троицк, Москва
На основании опыта поддержу оба совета больше вникать в специфику своей задачи, чем библиотек.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 14 Январь, 2013 20:43 

Зарегистрирован: Вторник, 30 Июнь, 2009 14:58
Сообщения: 1438
Иван Денисов писал(а):
А можно ли в HostFiles менять параметры:
Код:
nofbufs = 4;   (* max number of buffers per file *)
bufsize = 2 * 1024;   (* size of each buffer *)

? Кто пробовал?

Оперативной памяти ведь теперь на компах много, а вот обращение к жесткому диску хотелось бы пореже совершать, при использовании Files.

Самое оптимальное вроде под размер кластера (4 * 1024)
Больший размер не должен давать существенного ускорения. Но на всякий случай можно попробовать разные варианты. :)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 14 Январь, 2013 21:43 

Зарегистрирован: Вторник, 30 Июнь, 2009 14:58
Сообщения: 1438
Цитата:
Однако для обеспечения максимальной скорости обмена данными следует задавать длину, которая была бы кратна длине физического сектора дискового носителя информации (512 байт). Более того, фактически пространство на диске выделяется любому файлу порциями - кластерами, которые в зависимости от типа диска могут занимать 2 и более смежных секторов. Как правило, кластер может быть прочитан или записан за один оборот диска, поэтому наивысшую скорость обмена данными можно получить, если указать длину записи, равную длине кластера.
http://borlpasc.narod.ru/docym/Faronov/gl5/gl5_8.html

Про особенности работы подсистемы ввода-вывода Windows можно почитать у Марка Руссиновича:
http://royallib.ru/read/russinovich_mar ... tml#113321
Там несколько разных способов описано. В BlackBox используется самый простой.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 14 Январь, 2013 22:50 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9072
Откуда: Россия, Орёл
Это в теории кратно размеру сектора. Реально не подгадаете - между Вами и диском есть файловая система с её структурами. Вы считали блок в 1024 байта, он в реальности хрен знает как и во сколько кластеров ФС был отображён, а к каждому кластеру хрен знает сколько байт служебной информации могло быть. И вышло уже не 1024 байта, а 1124, и не в одном секторе диска, а в трёх... (условно говоря).
Также с ОЗУ - Вы в своём любимом языке делаете new массива длиной 4096 байт, думая, что это совпадает с размером страницы процессора, а сколько служебной информации держит на этот массив язык и менеджер кучи....
Правильнее не задумываться о таких особенностях, ибо они слишком преходящи.

-- пардон, у Вас в цитате как раз про размер кластера тоже сказано. Ну дык - и какой на Вашей ФС размер кластера? :) А если она, например, в VDS, в виртуальной файловой системе, что для серверов почти норма сегодня - сколько там отображений до уровня НЖМД? :)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 14 Январь, 2013 23:04 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 7946
Откуда: Троицк, Москва
Илья Ермаков писал(а):
Правильнее не задумываться о таких особенностях, ибо они слишком преходящи.
Притом, что усилия на их использование велики.

Не окупается.

Логика своей задачи -- вот что мощно окупается.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 14 Январь, 2013 23:05 

Зарегистрирован: Вторник, 30 Июнь, 2009 14:58
Сообщения: 1438
Можно не гадать, а просто проверить.
Думаю, что разработчики BB тоже делали под размер кластера (подозреваю что в те времена именно такой размер чаще всего и был).


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 14 Январь, 2013 23:09 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2546
Откуда: Россия, Ярославль
про витуальные общие файлы, про виртуальные общие файлы экземпляров ББ расскажите пжалуйста :)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 14 Январь, 2013 23:30 

Зарегистрирован: Вторник, 30 Июнь, 2009 14:58
Сообщения: 1438
А еще можно почитать "Проект Оберон" 7.3 Реализация файлов на диске.
И станет понятно, что Вирт тоже делал буфер по размеру кластера. И тоже ради максимальной производительности.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 15 Январь, 2013 00:07 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9072
Откуда: Россия, Орёл
Пётр Кушнир писал(а):
про витуальные общие файлы, про виртуальные общие файлы экземпляров ББ расскажите пжалуйста :)


Эх...
Жила-была такая абстракция - страничный буфер. Она была внутри построена над неуправляемой памятью (выделяемой средствами ОС) и хранила все заголовочные данные в этой памяти. Т.е. если другому страничному буферу давали тот же адрес начальной страницы, что использовался другим буфером, то он начинал работать с той же памятью. Плюс была секция критическая.
Т.е. два ББ, загруженные в общее адресное пространство, могли работать с общими страницами памяти через такие объекты.
Ну и дальше была реализация Files.File над таким страничным буфером.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 15 Январь, 2013 00:12 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2546
Откуда: Россия, Ярославль
Через неё бы шину сообщений пропустить и будет счастье. Такой чудесный компонент должен стать достоянием общественности :)
Насколько я понимаю из http://ru.wikipedia.org/wiki/Mmap, совместная память это кроссплатформенная концепция, то есть, при разработке линакс-версий, понадобится только переписать реализацию страничного буфера
эрлангеры, кстати, гордятся своей кластеризацией искаропки, чем мы хуже


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 15 Январь, 2013 00:57 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9072
Откуда: Россия, Орёл
Илья Ермаков писал(а):
Я бы повыкладывал конкретный код, не жалко, если бы он не был сильно завязан на свои библиотеки - да и "постарел" код за 4 года, сейчас уже есть намерения переделать с высоты сегодняшнего понимания :)


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 54 ]  На страницу 1, 2, 3  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
cron
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2019, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB