Article # 127, added by Geoworks, historical record
| first |
previous |
index |
next |
last |
Performance profiling your code in swat
Here's the Notepad data file (notepad.pdb) format, provided by HP. ========================================================================== Notepad data structures ----------------------- Notepad data is kept in a database file Each note has 5 different data items. They are name - an ascii text string representing the name of the note category - a category string in database defined format text - ascii text of the note text format - formatting data for the text ink - ink data Record Format ------------- Each note in the notepad database is represented by a TYPE_DATA record with the following format (low memory first) : DataRecordHeader optional zero terminated string optional zero terminated string where DataRecordHeader (in C notation) is : typedef struct { word DRH_nameOffset; word DRH_categoryOffset; sword DRH_text; sword DRH_textFormat; sword DRH_ink; char DRH_zeroTerminator; } DataRecordHeader; That is, there are 5 fields in a notepad database record. DRH_nameOffset is the byte offset from the start of record to a zero terminated string representing the name of the note. If there is no name, DRH_nameOffset points to DRH_zeroTerminator. DRH_categoryOffset is similar to DRH_nameOffset except that it points to the category string of the note. e.g. "friends;church". DRH_text has a integer value (>= 0) representing the record number of TYPE_NOTE in the database file which holds the null terminated ascii text of the note. If no ascii text exists, this value is -1. DRH_textFormat is similar to DRH_text except that it contains the record number of a (TYPE_USER+5) recordtype. The data it contains is formatting information for the text of the note. This will be described later. DRH_ink also contains a record number. The recordtype is (TYPE_USER+6). This contains the compressed ink data. This will also be described later. DRH_zeroTerminator is a byte value with a constant of zero. This provides a convenient null terminator for the name and category strings when there is no string. notepad will continue to load the ascii text pointed to by DRH_text even if DRH_textFormat is -1 (i.e., no text format). Fielddefs --------- The 5 fields have the following fielddefs : name - STRING_FIELD with field name "Title" category - CATEGORY_FIELD with field name "Category" text - NOTE_FIELD with field name "Note Text" text format - (USER_FIELD+5) with field name "Note Text Format" ink data - (USER_FIELD+6) with field name "Note Ink" The above field names exist in the US/UK version. These strings are localized for the various language versions because the Connectivity Pack picks up these names for display. The field def records are defined as in the order above so an alternate way of accessing the fielddefs (and looking at what the fields are) is to access via record number of TYPE_FIELDDEF records. Text Format Data structure -------------------------- It looks like this (low memory first) : NoteMergedTextFormatHeader char run array char element array para run array para element array In C notation NoteMergedTextFormatHeader looks like this typedef struct { word NMTFH_charRunArray; /* offset to char run array */ word NMTFH_charElementArray; /* offset to char elem array */ word NMTFH_paraRunArray; /* offset to para run array */ word NMTFH_paraElementArray; /* offset to para elem array */ } NoteMergedTextFormatHeader; Each item in NoteMergedTextFormatHeader is a byte offset to an array of structures. The char and paragraph run arrays describe ranges of text which get some particular text format. They are described in the Geoworks Objects Book chapter on text objects. Briefly they both look like this : TextRunArrayElement Number 0 TextRunArrayElement Number 1 .... where TextRunArrayElement is typedef struct { WordAndAHalf TRAE_position; /* text position */ word TRAE_token; /* points to an element in the corresponding element array */ } TextRunArrayElement; The element arrays are also described in GEOWORKS documentation. The storage of the char element array and the para element array differ (because the para element array has variably sized elements) The char element array looks like this : VisTextCharAttr element number 0 VisTextCharAttr element number 1 .... where each VisTextCharAttr represents a text format. The paragraph element array (as stored in the database) is a complete copy of the paragraph element array inclusive of header structure as per GEOWORKS documentation. Briefly it looks like this : TextElementArrayHeader word offset to element 0 word offset to element 1 .... word offset to element N VisTextParaAttr element 0 Tabs array VisTextParaAttr element 1 Tabs array .... VisTextParaAttr element N Tabs array Ink Format ---------- The format of the ink is that as described in the Geoworks documentation for the storage of ink using their DB routines. Basically it is a run length compression of the ink points. ======================================================================== Here's some information about the Phonebook file format. ======================================================================== A phone book record is a char buffer with the header formatted as follows: Bytes: 00-01 offset to Name field text 02-03 offset to Home field text 04-05 offset to Office field text 06-07 offset to Fax field text 08-09 offset to Other field text 0A-0B offset to Company field text 0C-0D offset to Title field text 0E-0F offset to Address1 field text 10-11 offset to Address2 field text 12-13 offset to Category field text 14-15 record index for Note 16 A null (zero) byte If a field contains an empty string, then its offset is set to the offset of the null byte (16h). The first non-empty string will have offset 17h, and its null-terminated string will begin at byte 17h (the next byte after the null byte). The next non-empty string will have an offset that points to the next byte after the null-terminator for the previous non-empty string. I have included some output for a sample record and some code that I hacked-up to see if it would work. I'm glad to say that it did. ----------------------------------------------------------------------- // read an existing record DB_ReadRecord(blockHandle, TYPE_DATA, theRecordNum,recordBuffer, RECORD_BUFFER_SIZE,&recSize); // Modify existing record and write back to file replacePhoneBookTextField(recordBuffer,&recSize,RECORD_BUFFER_SIZE, PHONEBOOK_HOME_FIELD_INDEX,"HOME PHONE"); DB_WriteRecord(blockHandle, TYPE_DATA,theRecordNum,recordBuffer, recSize,&viewPtIndex); // create a new record and add to file // see following routines below... initPhoneBookRecord(recordBuffer,&recSize); replacePhoneBookTextField(recordBuffer, &recSize, RECORD_BUFFER_SIZE, PHONEBOOK_NAME_FIELD_INDEX, "Bogus Record"); replacePhoneBookTextField(recordBuffer,&recSize, RECORD_BUFFER_SIZE, PHONEBOOK_OFFICE_FIELD_INDEX, "555-1212"); DB_AddRecord(blockHandle, TYPE_DATA, recordBuffer, recSize, &viewPtIndex); static void initPhoneBookRecord(char *recordBuffer,unsigned int *recSize) // initialize the record, return record size in recSize { PhoneBookHeaderPtr headerPtr; memset(recordBuffer,0,RECORD_BUFFER_SIZE); *recSize = EMPTY_PHONE_BOOK_RECORD_SIZE; // indicate no Note by setting a note index of 0xFFFF headerPtr = (PhoneBookHeaderPtr)recordBuffer; headerPtr->noteRecordIndex = 0xFFFF; } static Boolean replacePhoneBookTextField(char *recordBuffer,unsigned int *recSize,word bufSize,word fieldIndex,char *newText) /*** replace an entry in the record recordBuffer = buffer filled with record recSize = size of record, is set to new size after replacing bufSize = buffer size fieldIndex = which field to replace newText = new text to put into field returns TRUE if successful ***/ { word i,nbytes,destOffset,nullOffset,len; unsigned int newRecSize; PhoneBookHeaderPtr newHeader,oldHeader; char *tempBuffer,*srcPtr,*destPtr; ASSERT_IF(recordBuffer==NULL,"replacePhoneBookTextField - null recordBuffer"); ASSERT_IF(recSize==NULL,"replacePhoneBookTextField - null recSize"); ASSERT_IF(bufSize==0,"replacePhoneBookTextField - bufSize=0"); ASSERT_IF(fieldIndex>=10,"replacePhoneBookTextField - invalid fieldIndex"); ASSERT_IF(newText==NULL,"replacePhoneBookTextField - null newText"); // ASSUME max field length is 64 chars ASSERT_IF(strlen(newText)>64,"replacePhoneBookTextField - strlen>64"); /*** Right now, this function makes a temporary copy of the buffer, but it can be rewritten to replace the text in-place to save heap space ***/ // create temporary buffer to hold current buffer contents nbytes = *recSize; if (!allocateNewPtr(nbytes,(void **)&tempBuffer)) return(0); // copy old record contents into temp buffer memcpy(tempBuffer,recordBuffer,nbytes); // first bytes of buffer is the header oldHeader = (PhoneBookHeaderPtr) &tempBuffer[0]; newHeader = (PhoneBookHeaderPtr) &recordBuffer[0]; // set all record bytes to NULL memset(recordBuffer,0,bufSize); // reset noteRecordIndex newHeader->noteRecordIndex = oldHeader->noteRecordIndex; // build new contents of record nullOffset = sizeof(PhoneBookHeaderRecord); // offset to NULL byte newRecSize = (unsigned int)(nullOffset + 1); for (i=0;i<10;i++) { if (i==fieldIndex) srcPtr = newText; else srcPtr = &tempBuffer[oldHeader->offsetList[i]]; len = strlen(srcPtr); if (len==0) { // offset to null byte destOffset = nullOffset; } else { // offset to new string destOffset = newRecSize; // append string onto record destPtr = &recordBuffer[destOffset]; strcpy(destPtr,srcPtr); newRecSize += (len+1); } newHeader->offsetList[i] = destOffset; } // dispose of temp buffer disposePtr(tempBuffer); *recSize = newRecSize; return(TRUE); } ----------------------------------------------------------------------- RECORD HEADER>> 000f19: 0b 02 74 00 04 00 ..t... Type: 11 (TYPE_DATA) Status: 02 Length: 116 (0074) Record #: 4 Status = Modified RECORD>> 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0000: 17 00 16 00 22 00 2f 00 3c 00 16 00 16 00 16 00 ...."./.<....... . . i . . . . J o n H a r l a 0010: 16 00 69 00 04 00 00 4a 6f 6e 20 48 61 72 6c 61 ..i....Jon Harla n . 5 1 0 - 5 5 9 - 7 8 7 2 . 5 0020: 6e 00 35 31 30 2d 35 35 39 2d 37 38 37 32 00 35 n.510-559-7872.5 1 0 - 5 5 9 - 7 8 7 6 . 2 W A Y 0030: 31 30 2d 35 35 39 2d 37 38 37 36 00 32 57 41 59 10-559-7876.2WAY = 1 7 4 0 7 9 0 E M A I L = j 0040: 3d 31 37 34 30 37 39 30 20 45 4d 41 49 4c 3d 6a =1740790 EMAIL=j o n b o @ a o l . c o m P G R 0050: 6f 6e 62 6f 40 61 6f 6c 2e 63 6f 6d 20 50 47 52 onbo@aol.com PGR = 4 5 8 6 1 5 9 . N o n e . 0060: 3d 34 35 38 36 31 35 39 00 4e 6f 6e 65 00 =4586159.None. /*** PHONEBOOK FIELDS 0 - Name 1 - Home 2 - Office 3 - fax 4 - other 5 - company 6 - title 7 - address1 8 - address2 9 - category ***/ ======================================================================== Here's some information about the Jotter file format. ======================================================================== API for JOTTER ENGINE ======================== library: jotter include: Objects/jCntlC.h for the jotter control object include: hp.h for gcn lists, notification types author: cthomas This is the design document Jin Meng Tan and I have composed. There's lots of internal details that a developer will probably never touch, which I'll mark off. In fact, most of this is stuff a developer will never use, except for the section on creating an object that accepts a jotter page. The JotterControlClass objects work closely with the jotter app to coordinate the transfer of data between the jotter app and other objects. An application's JotterControlClass object is sort of a go-between for the jotter app and specific objects inside the app. Jotter Engine Design Specifications dated 29th Sep ================================================== Class: JotterControlClass No external messages. 1. JOTTER STUCK PAGE FORMAT 1.1. Stuck Page Block The VM block containing the currently stuck page has the VM User ID JOTTER_STUCK_PAGE_USER_ID, and will reside in the system clipboard file. If there is no currently stuck, page, then no such VM block will exist. ***************** Internal details ****************************** 1.2. Stuck page format The structure of the stuck page will be a root VMChainTree block with 2 immediate children. This block will have a UserID of JOTTER_STUCK_PAGE_USER_ID. The first child will be the text transfer item created with MSG_VIS_TEXT_CREATE_TRANSFER_FORMAT. The second child will be the ink data DB item created with MSG_INK_SAVE_TO_DB_ITEM. Structure of the VMChainTree in the header block will be typedef struct { VMChainTree NTIH_vmChainTree; /* offsets from start of block to the name/category strings */ /* set to zero if name/category does not exist */ word NTIH_nameOffset; word NTIH_categoryOffset; /* cached information about the data */ Boolean NTIH_textIsEmpty; Boolean NTIH_inkIsEmpty; } NoteTransferItemHeader; The structure of the entire (generic) header block will be (lowest address first) : NoteTransferItemHeader Null Terminated Name Ascii String Null Terminated Category Ascii String VMChain pointer to text transfer item DBGroupAndItem pointer to Ink DB Item In the case of the stuck page, both name and category will not be supported currently. Thus the structure will look like : NoteTransferItemHeader VMChain pointer to text transfer item DBGroupAndItem pointer to Ink DB Item and NTIH_nameOffset = NTIH_categoryOffset = 0; The text transfer item itself is a VMChain subtree with leaf blocks containing various information but the user should not need to know this. The text transfer item can be retrieved into a text object with a call to MSG_VIS_TEXT_REPLACE_WITH_TEXT_FORMAT There will always be 2 children of the root, even if there is no data to store. For example, even if the stuck page has only ink, there will still be 2 blocks with the text DB item having no text data. 1.2.1 Operations on stuck page A stuck page can be copied with VMCopyVMChain() A stuck page can be destroyed with VMFreeVMChain(). When using quick transfer, this structure is preserved (the Jotter controller does the VMCopyChain for the application) and its head is passed as the transfer item. NoteClass will have a method called MSG_NOTE_LOAD_FROM_TRANSFER_FORMAT which will load the text and ink data when passed the VMChain handle. It will also have a corresponding MSG_NOTE_SAVE_TO_TRANSFER_FORMAT but applications are not expected to use this as the main storage method for NoteFields is the Jedi specific database engine. ************************ END of INTERNAL stuff *********************** 2. JOTTER NOTIFICATIONS 2.1. Jotter GCN lists The Jotter Application will communicate with JotterControl objects through the jotter GCN list. This is a system GCN list, and has the following notification ID: manufacturer id = MANUFACTURER_ID_HP (insert specific value here) GCN list type = JGCNSLT_JOTTER In addition, each application's Jotter Control object will reside on an application GCN list, called the "application jotter GCN list". This list will be used by objects within an application to communicate with the application's JotterControl object, and is identified by the following constants: manufacturer id = MANUFACTURER_ID_HP GCN list type = JGAGCNLT_JOTTER Every jotter control will automatically place themselves on both of these lists. 2.2. Jotter GCN List Messages The only message used to communicate with objects on the jotter GCN list is MSG_META_NOTIFY, with one of the following possible notification types passed as a parameter: (of type JediNotificationType) JNT_STUCK_PAGE_CHANGED JNT_JOTTER_CONTROL_SHRINK JNT_JOTTER_CONTROL_DONT_SHRINK (internal to JotterControlClass) JNT_JOTTER_CAPABLE_OBJECT_TARGETABLE JNT_JOTTER_CAPABLE_OBJECT_NOT_TARGETABLE 2.2.1. JNT_STUCK_PAGE_CHANGED notification type *** Only sent by the jotter control object or the jotter app *** This notification type is sent when the status of the stuck page has changed (i.e., when a page has been "stuck" by the jotter application, or the stuck page has been pasted, thereby removing the stuck page). Upon receiving a MSG_META_NOTIFY with JNT_STUCK_PAGE_CHANGED as the notification type parameter, an object may wish to determine whether or not there is a stuck page by using: VMFind(, 0, JOTTER_STUCK_PAGE_USER_ID) (returns the null handle if the block doesn't exist) 2.2.2. JNT_JOTTER_CONTROL_SHRINK *** Only sent by the jotter app *** The Jotter Application will send this notification type when the user presses "Stick". A JotterControl object which receives this notification will set its own state such that the next time it becomes visible (or immediately if it is already visible), it will produce the animated shrink lines specified in the ERS. (call this the shrink state) 2.2.3. JNT_JOTTER_CONTROL_DONT_SHRINK *** Sent by jotter control object to other jotter control objects **** This notification type is sent by the JotterControl which has animated the shrink lines to other JotterControls on the jotter GCN list. When a JotterControl receives this message while it is the shrink state, it will remove itself from the shrink state, effectively preventing itself from showing the shrink lines. Without this interaction between JotterControls, Jotter Controls that become visible later would perform the shrink function, even though it had already been performed. 2.2.4. JNT_JOTTER_CAPABLE_OBJECT_{NOT_}TARGETABLE *** Objects which can receive a jotter page via dragging the jotter *** icon into them, must send these notifications. When receiving this notification type, the jotter control will: - Enable itself when receiving JNT_JOTTER_CAPABLE_OBJECT_TARGETABLE - Disable itself when receiving JNT_JOTTER_CAPABLE_OBJECT_NOT_TARGETABLE These notifications are sent by objects of an application to the application GCN list. 3. APPLICATION SUPPORT OF JOTTER 3.1. Application programmer support of the Jotter Exactly one JotterControlClass object must be in the generic tree of every application, as a child of the application's GenPrimary object. 3.2. Object Support of the Jotter. 3.2.1. Drag and Drop Support The dropping of the Jotter Icon into applications will make use of GEOS' quick-transfer mechansim, with certain changes to allow for the fact that a pen-based system has no equivalent of a right mouse button with which to control a quick transfer. The JotterControl object will initiate the quick-transfer when a stuck jotter page is available, and the user has held down the jotter icon in the application's title bar. It will do this by registering the block with the ID JOTTER_STUCK_PAGE_USER_ID as the current quick transfer item. As destinations of quick-transfer, objects which support pasting of the stuck jotter page have the following responsibilities: *** This is very much like the description of quick transfer *** in the concepts book. 1) When the potential destination receives MSG_META_PTR, it should use ClipboardGetQuickTransferStatus() to determine if a quick transfer is in effect. If it is, it must use ClipboardQueryItem() to determine if the item being transfered is a jotter page (ClipboardItemFormat CIF_NOTE, Manufacturer id MANUFACTURER_ID_HP) 2) The object should grab the mouse, and the gadget exclusive (via MSG_VIS_TAKE_GADGET_EXCL ) directing further MSG_META_PTR messages to the potential destination. It will call ClipboardSetQuickTransferFeedback(CQNF_MOVE). 3) In this, and subsequent invocations of the MSG_META_PTR method, the destination should provide any desired user feedback (for note fields, a line drawn around the perimeter of the note. for tables, a box drawn around the row under the pen). 4) If the object receives MSG_META_PTR with the UIFA_IN flag clear, or receives the MSG_VIS_LOST_GADGET_EXCLUSIVE, then the object must relinquish the mouse grab, and re-transmit the pointer event (by returning MRF_REPLAY from the MSG_META_PTR handler). 5) When the destination receives MSG_META_END_SELECT, it should determine if a jotter paste is in effect (as in 1). It should grab the jotter page from the quick-transfer clipboard with ClipboardRequestItemFormat(), paste the jotter page data, and call ClipboardEndQuickTransfer(), passing CQNF_MOVE. 3.2.1.1. Table Support of Jotter Additional details (referring to points 1-5 from 3.2.) 1) The table goes into "external" drag and drop mode. (which provides the row-outlining behavior) 4) The table goes back into "internal" drag and drop mode. 5) The table has either been subclassed to provide a handler for pasting jotter pages, or calls some other object to perform the paste. (like a NoteClass object). 3.2.1.2. Note Field Support of Jotter Additional details (referring to points 1-5 from 3.2.) 3) The note field draws an outline around its perimeter 3.2.2. Jotter Control Enabling Support In order that an application's Jotter Control object can know when an object capable of supporting jotter paste is visible, some communication from such objects to the application's Jotter Control is needed. When an object that supports jotter becomes available to the user (i.e., comes on-screen), it will send MSG_META_NOTIFY with the JotterNotificatonType JNT_JOTTER_CAPABLE_OBJECT_TARGETABLE to the application jotter GCN list. When the object becomes unavailable to the user, it will send JNT_JOTTER_CAPABLE_OBJECT_NOT_TARGETABLE. The receiving JotterControl will then know when is supported by some piece of user interface on the screen of the application, and can draw itself appropriately when a stuck page is available. *********** This text taken from Objects/jCntlC.goh ****************** ** If you happen to look in jCntlC.goh, ignore item 1 2) In order that the jotter control can know when it should enable and disable itself: All objects into which the jotter icon may be dropped must send: MSG_META_NOTIFY(manufacturer id = MANUFACTURER_ID_HP, notification type = JNT_JOTTER_CAPABLE_OBJECT_TARGETABLE) to the application GCN list: manufacturer id = MANUFACTURER_ID_HP GCN list type = JGAGCNLT_JOTTER when the object becomes interactable to the user. This can be done when the object recieves a MSG_VIS_OPEN, or by using the Gen visibility mechanism (Objects 2.6.1.5). 3) All objects into which the jotter icon may be dropped must send: MSG_META_NOTIFY(manufacturer id = MANUFACTURER_ID_HP, notification type = JNT_JOTTER_CAPABLE_OBJECT_NOT_TARGETABLE) to the application GCN list: manufacturer id = MANUFACTURER_ID_HP GCN list type = JGAGCNLT_JOTTER when the user can no interact with it. This can be done when the object recieves a MSG_VIS_CLOSE, or by using the Gen visibility mechanism (Objects 2.6.1.5). 4) If a full screen object (as in 1) containing no jotter capable objects is going to obscure another screen that does contain such objects, then the screen to be obscured must be dismissed. If the obscured screen isn't closed, but simply obscured, then the objects on the obscured screen will never know that they are not visible to the user, and will not send the message described in 3. The jotter icon in the new screen will be enabled, even though there are no visible objects that will take the icon. ====================================================================== The following swat commands can help you in finding areas in your code that need optimizing. timebrk Manipulates breakpoints that calculate the amount of time executing between their starting point and a specified ending point. The breakpoints also record the number of times their start is hit, so you can figure the average amount of time per hit. tbrk Manipulates breakpoints that tally the number of times they are hit without stopping execution of the machine -- the breakpoint is noted and the machine is immediately continued. Such a breakpoint allows for real-time performance analysis. cycles Counts the number of machine cycles a given set of instructions takes to execute on a particular processor.