Переключение на Главную Страницу Страницы: 1 ОтправитьПечать
Горячая тема (более 10 ответов) Таинственный Моксель (число прочтений - 7736 )
Uzhast
1c++ power user
Отсутствует



Сообщений: 1341
Зарегистрирован: 30. Августа 2006
Пол: Мужской
Таинственный Моксель
16. Марта 2007 :: 00:05
Печать  
Провел определенные исследования, которые могут представлять интерес в свете этой темы: http://www.1cpp.ru/forum/YaBB.pl?num=1172758634

Итак, в теме пришли к выводу, что в ячейки Мокселя можно запихать не более 32К символов. Такие выводы были сделаны на основе таких данных:
1) В документации из 1L указано, что для хранения длины текста используется 1 или 2 байта.
2) В редакторе можно в ячейку запихнуть не более 32К текста, что соответствует максимальному знаковому значению длиной 2 байта.

Сейчас натолкнулся на такой код сериализации CString в классе CArchive:
Код
Выбрать все
CArchive& AFXAPI operator<<(CArchive& ar, const CString& string)
{
	// special signature to recognize unicode strings
#ifdef _UNICODE
	ar << (BYTE)0xff;
	ar << (WORD)0xfffe;
#endif

	if (string.GetData()->nDataLength < 255)
	{
		ar << (BYTE)string.GetData()->nDataLength;
	}
	else if (string.GetData()->nDataLength < 0xfffe)
	{
		ar << (BYTE)0xff; // не правда ли, что-то напоминает?
		ar << (WORD)string.GetData()->nDataLength;
	}
	else
	{
		ar << (BYTE)0xff;
		ar << (WORD)0xffff; // а отсюда следует, что длина текста может быть равна 2^32
		ar << (DWORD)string.GetData()->nDataLength;
	}
	ar.Write(string.m_pchData, string.GetData()->nDataLength*sizeof(TCHAR));
	return ar;
}
 



Тут я и вспомнил, что когда-то слышал про некоторые ограничения полей ввода винды. Может быть, в ячейку нельзя запихнуть больше 32К из-за этого? Написал простой тестовый код:
Код
Выбрать все
Процедура Сформировать()
	Т = СоздатьОбъект ("Таблица");
	Стр = "";
	Для Ч = 1 По 1000 Цикл
		Стр = Стр + "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890";
	КонецЦикла;
	Сообщить ("" + СтрДлина (Стр));
	Т.Область (1, 1).Текст = Стр;
	Т.Записать ("E:/temp/test.mxl");

	Т = 0;
	Т = СоздатьОбъект ("Таблица");
	Т.Открыть ("E:/temp/test.mxl");
	Стр = "";
	Стр = Т.Область (1, 1).Текст;
	Сообщить ("" + СтрДлина (Стр));
КонецПроцедуры
 


Угадайте, что он выводит? Подмигивание Впрочем ладно. Он выводит:
Цитата:
87000
87000

Т.е. Моксель таки поддерживает до 4 гигов на текст ячейки (хотя и никогда не сможет записать такой файл, т.к. таблица сначала должна как-то поместиться в памяти).

Примечательно, что для хранения длины текста используется такой вот набор байт:
FF FF FF D8 53 01 00. Что несколько отличается от документации по 1L. Вот такой он хитрый этот Моксель. На маленьких наборах данных изучать формат бесполезно - выводы, сделанные на основе изучения небольших файликов приводят к некорректной работе с большими файлищами Подмигивание
  
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: Таинственный Моксель
Ответ #1 - 16. Марта 2007 :: 13:35
Печать  
Наверняка ты прав, хранение данных и сериализация - это CString.

Вообще, формат mxl теперь отлично документирован.
Только не очень понятно, для ячейки:

class IMPORT_1C CSheetCell : public CSheetFormat
{
DECLARE_DYNCREATE(CSheetCell)

public:
     CString csValue;                              // 0x24      ; сериализуется, если dwFlags & 0x80000000
     CString csDescr;                              // 0x28      ; сериализуется, если dwFlags & 0x40000000
     CString cs_2C;                                    // 0x2C      ; сериализуется, если dwFlags & 0x20000000
     CByteArray ByteArray_30;                        // 0x30      ; сериализуется, если dwFlags & 0x00200000 и версия > 3

третий CString и ByteArray для чего могут использоваться?
может, где-то и встречается, но пока что-то не попадалось.
  

De quelle planète es-tu?
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: Таинственный Моксель
Ответ #2 - 16. Марта 2007 :: 13:41
Печать  
Кстати, 4Г на ячейку - это круто, конечно, но нельзя забывать, что CString - это CFixedAlloc, а CFixedAlloc - это статическое выделение памяти.
Т.е. забив однажды суммарно пару гигабайт в CString, working set процесса так и останется висеть на пару гигабайт, даже после их разрушения.

Кстати, почему-то это еще и влияет на общую производительность системы.
Когда в свое время возились с оптимизацией IndexedTable, это было очень хорошо заметно.
  

De quelle planète es-tu?
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: Таинственный Моксель
Ответ #3 - 17. Марта 2007 :: 11:52
Печать  
По поводу торможения мокселя на объемных таблицах.

В реализации встречаются алгоритмы характера О(n) (надеюсь, что не хуже).
К примеру, хранение мержлиста (соответствий объединенных ячеек) реализовано через CList<RECT>.

При этом интересно, что общее хранение информации весьма неплохо сделано.
Незанятые ячейки памяти не занимают, а для хранения строк и ячеек применены алгоритмы характера O(log2(n)).

Так что рекомендация простая: поменьше объединений и побольше пустых строк и ячеек Улыбка
  

De quelle planète es-tu?
Наверх
 
IP записан
 
Uzhast
1c++ power user
Отсутствует



Сообщений: 1341
Зарегистрирован: 30. Августа 2006
Пол: Мужской
Re: Таинственный Моксель
Ответ #4 - 17. Марта 2007 :: 12:12
Печать  
kms писал(а) 16. Марта 2007 :: 13:35:
Наверняка ты прав, хранение данных и сериализация - это CString.

Скорее, CArchive Улыбка. А MXL - это результат сериализации CSheetDoc (или чего-то в этом роде).

kms писал(а) 16. Марта 2007 :: 13:35:
Вообще, формат mxl теперь отлично документирован.

Нет, пока не будет полного парсера, так говорить нельзя. И то некоторые детали могут ускользнуть.

kms писал(а) 16. Марта 2007 :: 13:35:
Только не очень понятно, для ячейки:

class IMPORT_1C CSheetCell : public CSheetFormat
{
DECLARE_DYNCREATE(CSheetCell)

public:
     CString csValue;                              // 0x24      ; сериализуется, если dwFlags & 0x80000000
     CString csDescr;                              // 0x28      ; сериализуется, если dwFlags & 0x40000000
     CString cs_2C;                                    // 0x2C      ; сериализуется, если dwFlags & 0x20000000
     CByteArray ByteArray_30;                        // 0x30      ; сериализуется, если dwFlags & 0x00200000 и версия > 3

третий CString и ByteArray для чего могут использоваться?
может, где-то и встречается, но пока что-то не попадалось.

Может, это для таблиц в режиме ввода данных? Вообще, флаги похожи на флаги из MXL. У меня они пока выглядят так:
Код
Выбрать все
enum MoxcelCellFlags {
	cfValue =				0x40000000,
	cfText =				0x80000000,
	cfPattern =				0x00010000,
	cfPatternColor =		0x00020000,
	cfControl =				0x00040000,
	cfType =				0x00080000,
	cfProtect =				0x00100000,
	cfBorderBottom =		0x00000100,
	cfPicturePrint =		0x00000100,
	cfBorderColor =			0x00000200,
	cfColumnPagePosition =	0x00000400,
	cfColumnWidth =			0x00000800,
	cfRowHeight =			0x00000400,
	cfAlignH =				0x00001000,
	cfAlignV =				0x00002000,
	cfFontColor =			0x00004000,
	cfBackground =			0x00008000,
	cfFontName =			0x00000001,
	cfFontSize =			0x00000002,
	cfFontBold =			0x00000004,
	cfFontItalic =			0x00000008,
	cfFontUnderline =		0x00000010,
	cfBorderLeft =			0x00000020,
	cfPictureBorderStyle =	0x00000020,
	cfBorderTop =			0x00000040,
	cfPictureBorderWidth =	0x00000040,
	cfBorderRight =			0x00000080,
	cfPictureBorderColor =	0x00000080 // ??
};
 


Используются еще не все. Очевидно, здесь есть большие пробелы Улыбка

kms писал(а) 17. Марта 2007 :: 11:52:
По поводу торможения мокселя на объемных таблицах.

В реализации встречаются алгоритмы характера О(n) (надеюсь, что не хуже).
К примеру, хранение мержлиста (соответствий объединенных ячеек) реализовано через CList<RECT>.

При этом интересно, что общее хранение информации весьма неплохо сделано.
Незанятые ячейки памяти не занимают, а для хранения строк и ячеек применены алгоритмы характера O(log2(n)).

Так что рекомендация простая: поменьше объединений и побольше пустых строк и ячеек Улыбка

У меня для объединений тоже список используется. Только не CList, а std::list Улыбка. Вот только для ячеек у меня есть поле - ссылка на объединение, к которому ячейка принадлежит. Поэтому отрисовка листа с объединениями очень быстрая получилась - просто обходим строки видимых ячеек и попутно составляем список видимых объединений. Потом отрисовываем только видимые объединения. БОльший расход памяти (не такой уж большой), но зато независимость скорости отрисовки фрагмента листа от объема всего листа.

Хранение данных ячеек у меня аналогично Улыбка Используется вектор указателей. Если ячейка не определена, то указатель, естественно, NULL Улыбка Правда, у такого подхода недостаток - не очень высокая скорость вставки большого количества ячеек. В случае вектора не указателей, а вектора ячеек, выделение памяти происходило бы только один раз при вставке, например, 1000 ячеек. А так придется для каждой ячейки отдельно выделять память. (Но, в принципе, это можно будет обойти, если это станет узким местом.)
  
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: Таинственный Моксель
Ответ #5 - 17. Марта 2007 :: 12:49
Печать  
Uzhast писал(а) 17. Марта 2007 :: 12:12:
kms писал(а) 16. Марта 2007 :: 13:35:
Наверняка ты прав, хранение данных и сериализация - это CString.

Скорее, CArchive Улыбка. А MXL - это результат сериализации CSheetDoc (или чего-то в этом роде).

конкретно CArchive & operator<<(CArchive &,CString const &)

Цитата:
Может, это для таблиц в режиме ввода данных?

maybe, надо будет проверить

Цитата:
Вообще, флаги похожи на флаги из MXL. У меня они пока выглядят так:

Дык, они самые и есть Подмигивание

kms писал(а) 17. Марта 2007 :: 11:52:
По поводу торможения мокселя на объемных таблицах.

Там еще один конкретный косяк нашелся, чуть ниже напишу

Цитата:
У меня для объединений тоже список используется. Только не CList, а std::list Улыбка. Вот только для ячеек у меня есть поле - ссылка на объединение, к которому ячейка принадлежит.

Это грамотно, наверное.
Памяти-то не жалко, плохо, когда алгоритмы изначально немасштабируемые.

Цитата:
Хранение данных ячеек у меня аналогично Улыбка Используется вектор указателей. Если ячейка не определена, то указатель, естественно, NULL Улыбка Правда, у такого подхода недостаток - не очень высокая скорость вставки большого количества ячеек. В случае вектора не указателей, а вектора ячеек, выделение памяти происходило бы только один раз при вставке, например, 1000 ячеек. А так придется для каждой ячейки отдельно выделять память. (Но, в принципе, это можно будет обойти, если это станет узким местом.)

У них даже NULL не хранится Улыбка Там построено на списках соответствий ключей и значений.
Я сперва думал, что потери как раз на поиске соответствий, но нет, там все нормально.

Интригует, как это все у тебя получится.
Штука нужная, интересно будет посмотреть.
  

De quelle planète es-tu?
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: Таинственный Моксель
Ответ #6 - 17. Марта 2007 :: 13:04
Печать  
kms писал(а) 17. Марта 2007 :: 11:52:
По поводу торможения мокселя на объемных таблицах.

В реализации встречаются алгоритмы характера О(n) (надеюсь, что не хуже).
К примеру, хранение мержлиста (соответствий объединенных ячеек) реализовано через CList<RECT>.

При этом интересно, что общее хранение информации весьма неплохо сделано.
Незанятые ячейки памяти не занимают, а для хранения строк и ячеек применены алгоритмы характера O(log2(n)).

Так что рекомендация простая: поменьше объединений и побольше пустых строк и ячеек Улыбка


НебольшоеУлыбка уточнение

На самом деле характеристика затрат в O(n) применима только к ячейкам, которые участвуют в объединении.
Для ячеек, которые не участвуют в объединении затраты всегда составляют O(nMax), где nMax - общее количество объединений в таблице.

К примеру, возьмем таблицу в 100000 строк из 20 колонок.
Это 2000000 ячеек.
Если у нас объединены первая и вторая ячейки - это 100000 записей в мержлисте (nMax).

Для того, чтобы вывести строку n потребуются затраты на поиск объединения.
Они составят 2*O(n) + 18*O(nMax).

Таким образом, для широких (много колонок) таблиц, даже переменная величина затрат не несет определяющей роли, основные затраты приходятся произведение (nВсегоКолонок - nОбъединенныхЯчеекВКолонке)*O(nMax).

Поэтому проматывать первые строки также тяжело, как и последние. Отличие в процентах.

Такие дела.

Так что рекомендация совсем простая: большое общее число колонок и объединение ячеек несовместимы.

В стандартном мокселе, конечно Улыбка
  

De quelle planète es-tu?
Наверх
 
IP записан
 
Uzhast
1c++ power user
Отсутствует



Сообщений: 1341
Зарегистрирован: 30. Августа 2006
Пол: Мужской
Re: Таинственный Моксель
Ответ #7 - 18. Марта 2007 :: 21:43
Печать  
kms писал(а) 17. Марта 2007 :: 12:49:
У них даже NULL не хранится Улыбка Там построено на списках соответствий ключей и значений.
Я сперва думал, что потери как раз на поиске соответствий, но нет, там все нормально.

Ни фига ж себе ты Моксель прокачал Улыбка

Мне кажется, моксельный путь даст некоторый выигрыш на небольших разреженных таблицах. А на здоровых плотных таблицах ничего хорошего не будет. Если, например, они хранят в CMap индексы + сами ячейки/строки (а не указатели), то в плотно набитой таблице для каждой строки/ячейки будет индекс. По занимаемой памяти будет эквивалентно варианту с вектором указателей, а время доступа будет больше (расчет хеша + поиск по хешу). Плюс, не понятно, что у них за хеш-функция - вдруг, например, на каждой 10-й ячейке она дает одинаковый хеш? Тогда для разреженной таблицы, где данные есть только в каждой 10-й ячейке, CMap выродится в список со всеми вытекающими Улыбка

Если они хранят индекс+указатель на данные ячейки/строки, то у них даже будет некоторый оверхед по памяти Улыбка

Посмотрел сериализацию CMap. Там сначала делается CArchive::WriteCount, а потом пишутся ключи и значения попарно. А у 1С сначала делается WriteCount, затем пишутся все ключи, затем опять WriteCount, а потом данные строк/ячеек. Либо у меня с 1С версии MFC расходятся, либо у них переопределенная сериализация. Поэтому, складывается впечатление, что у них таки хранится CMap с указателями на ячейки/строки (или какой-нибудь альтернативный вариант используется).
  
Наверх
 
IP записан
 
Uzhast
1c++ power user
Отсутствует



Сообщений: 1341
Зарегистрирован: 30. Августа 2006
Пол: Мужской
Re: Таинственный Моксель
Ответ #8 - 18. Марта 2007 :: 22:06
Печать  
Хм, а скорее всего (судя по сериализации), у них либо 2 CList, либо 2 CArray (один с ключами, один со строками/ячейками). Если у них CList, то это было бы совсем смешно, поэтому будем считать, что CArray Улыбка По любому, скорость доступа к произвольной строке/ячейки будет хуже, чем в случае вектора с указателями Улыбка
  
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: Таинственный Моксель
Ответ #9 - 18. Марта 2007 :: 22:35
Печать  
Uzhast писал(а) 18. Марта 2007 :: 21:43:
Мне кажется, моксельный путь даст некоторый выигрыш на небольших разреженных таблицах.

Ага. Только где ж их взять... небольших-то, разреженных... Улыбка

Цитата:
Если они хранят индекс+указатель на данные ячейки/строки, то у них даже будет некоторый оверхед по памяти Улыбка

Так точно, и согласен, что и минус по скорости.
Цитата:
Либо у меня с 1С версии MFC расходятся, либо у них переопределенная сериализация. Поэтому, складывается впечатление, что у них таки хранится CMap с указателями на ячейки/строки (или какой-нибудь альтернативный вариант используется).

Сериализация, конечно, переопределенная.
Но я вначале говорил не о сериализации таблицы целиком, а о сериализации пары строк - значении и расшифровки.
Они реально хранятся в CString и через CString же и сериализуются (при сериализации ячейки), поэтому думаю, твое предположение о максимальном размере строки в 4Г верное.
  

De quelle planète es-tu?
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: Таинственный Моксель
Ответ #10 - 18. Марта 2007 :: 22:50
Печать  
Uzhast писал(а) 18. Марта 2007 :: 22:06:
Хм, а скорее всего (судя по сериализации), у них либо 2 CList, либо 2 CArray (один с ключами, один со строками/ячейками). Если у них CList, то это было бы совсем смешно, поэтому будем считать, что CArray Улыбка

В десятку. Улыбка
СSortArray называется - шаблон из двух сортированных массивов.
Поэтому и время доступа не const, а O(log2).

Но по сравнению с мержлистами, это завсегда везде ништяк.

Цитата:
По любому, скорость доступа к произвольной строке/ячейки будет хуже, чем в случае вектора с указателями Улыбка

Ты же не думаешь, что я выступаю адвокатом их реализации.
Ну не, я же знаю, что у тебя получится лучше. Улыбка

P.S.
Самое главное: отведи на цвет фона не один байт, а хотя бы три. Очень довольный
  

De quelle planète es-tu?
Наверх
 
IP записан
 
Uzhast
1c++ power user
Отсутствует



Сообщений: 1341
Зарегистрирован: 30. Августа 2006
Пол: Мужской
Re: Таинственный Моксель
Ответ #11 - 18. Марта 2007 :: 22:55
Печать  
kms писал(а) 18. Марта 2007 :: 22:50:
Самое главное: отведи на цвет фона не один байт, а хотя бы три. Очень довольный

Само собой Подмигивание
  
Наверх
 
IP записан
 
Uzhast
1c++ power user
Отсутствует



Сообщений: 1341
Зарегистрирован: 30. Августа 2006
Пол: Мужской
Re: Таинственный Моксель
Ответ #12 - 12. Октября 2007 :: 01:36
Печать  
Свежие (возможно) новости.
Сейчас обнаружил, что Моксель-то наш, оказывается, хитрая сволочь. Оказывается, что в Моксель нормально вставляются картинки формата EMF и WMF. А я думал, что он кроме BMP ничего не поддерживает... А вот джипеги он точно конвертирует в BMP.

Также напоролся на прикол с производительностью. Играюсь с тестовым файлом mxl весом 80Мб. Сначала Моксель открывает его меньше, чем за 3 секунды. Это очень хороший результат. У меня минимум получалось 5 секунд. Сейчас 8 секунд. Зато потом, если Мокселем тестовый файл открыть повторно, то он будет открываться уже почти 2 минуты! Память съедается примерно в таком же объеме.

Да! А вы знаете, что была такая страна - "Моксель"? Очень довольный
http://ukrlife.org/main/evshan/moxel_24.htm
  
Наверх
 
IP записан
 
Переключение на Главную Страницу Страницы: 1
ОтправитьПечать