Ben Langhinrichs

Photograph of Ben Langhinrichs

E-mail address - Ben Langhinrichs






April, 2004
SMTWTFS
    01 02 03
04 05 06 07 08 09 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30

Search the weblog





























Genii Weblog


Civility in critiquing the ideas of others is no vice. Rudeness in defending your own ideas is no virtue.


Tue 27 Apr 2004, 10:43 PM
Sparked by some questions about my earlier post, I have done some additional investigation, and noticed that others have made the same dumb assumption I have when investigating Lsi_info and its possible parameters:

For i = 1 to 255
  Print "Lsi_info(" & i & ")=" & Lsi_info(i)
Next i

Look familiar?  On codestore.net, Jake had this similar code:
For i=0 To 255
Print Cstr(i) & "=" & Lsi_info(i) & "<BR>"
Next

Unfortunately it's almost impossible to speculate on the meaning of each of the variables, so was near useless...
and I have seen several others with the same basic code.  On a whim today, I changed this to go up to 32760.  While there was nothing after 442, there were several interesting values after 255, incliding True and False values.  The complete list for that one run I made is at the bottom of this post, but here is what I need from readers.  Take the code:

Dim vals(500) as String
For i = 1 to 500
  vals(500) = Cstr(Lsi_info(i))
Next i

or something similar and run it in various places.  You may or may not want to ignore the blank or zero entries.  If I get a few samples from people running on a Mac or on a server under Linux or in a scheduled agent vs. a manual agent, we may be able to determine what a few more of these mean.  If  you will help, I'll be happy to maintain a more definitive list.  Anybody willing?  Please send results to  so I can put them together in a single table.

The complete list of non-zero, non-blank items
Lsi_info(1)='28'
Lsi_info(2)='INITIALIZE'
Lsi_info(3)='*1BEC110'
Lsi_info(4)='14901208'
Lsi_info(5)='15817068'
Lsi_info(6)='5.0.0.06'
Lsi_info(7)='24'
Lsi_info(8)='40637988'
Lsi_info(9)='en'
Lsi_info(11)='28'
Lsi_info(12)='INITIALIZE'
Lsi_info(13)='*1BEC110'
Lsi_info(14)='*1BEC110,INITIALIZE,17 '
Lsi_info(16)='15817164'
Lsi_info(17)='15816940'
Lsi_info(18)='15817052'
Lsi_info(19)='15817052'
Lsi_info(20)='15817132'
Lsi_info(30)='4'
Lsi_info(31)='4'
Lsi_info(32)='4'
Lsi_info(33)='4'
Lsi_info(50)='1146436'
Lsi_info(51)='1317169'
Lsi_info(52)='1487'
Lsi_info(98)='1000'
Lsi_info(99)='29981576'
Lsi_info(110)='170716'
Lsi_info(111)='186652'
Lsi_info(112)='16'
Lsi_info(113)='170716'
Lsi_info(114)='752'
Lsi_info(115)='12288'
Lsi_info(116)='18'
Lsi_info(117)='752'
Lsi_info(119)='4096'
Lsi_info(123)='4096'
Lsi_info(126)='931048'
Lsi_info(127)='1015829'
Lsi_info(128)='420'
Lsi_info(129)='931048'
Lsi_info(130)='664'
Lsi_info(131)='4096'
Lsi_info(132)='10'
Lsi_info(133)='664'
Lsi_info(201)='54529'
Lsi_info(202)='54552'
Lsi_info(203)='54590'
Lsi_info(204)='54618'
Lsi_info(205)='54648'
Lsi_info(206)='54656'
Lsi_info(207)='54683'
Lsi_info(208)='54711'
Lsi_info(209)='54728'
Lsi_info(400)='-441381'
Lsi_info(403)='4'
Lsi_info(404)='False'
Lsi_info(405)='False'
Lsi_info(406)='False'
Lsi_info(407)='False'
Lsi_info(408)='202'
Lsi_info(409)='2147483584'
Lsi_info(410)='True'
Lsi_info(411)='2000'
Lsi_info(412)='50'
Lsi_info(419)='4'
Lsi_info(420)='17'
Lsi_info(421)='INITIALIZE'
Lsi_info(422)='60'
Lsi_info(430)='17'
Lsi_info(431)='INITIALIZE'
Lsi_info(432)='60'
Lsi_info(440)='W32I'
Lsi_info(441)='W32I'
Lsi_info(442)='5'

Copyright © 2004 Genii Software Ltd.

Tue 27 Apr 2004, 02:45 PM
While it is not a well kept secret, the undocumented Lsi_info function in LotusScript has secrets within secrets.  There is actually a file called LSPRCVAL.LSS in your Notes directory which lists a number of constants for Lsi_info (see the bottom of this post for the 6.0.2 version), but besides these documented constants for the undocumented function, there are undocumented constants.  I am going to concentrate on three that help significantly when tracking memory loss.  This is an issue that is near and dear to my heart since I develop C/C++ extensions and LSXs, and while this may shock you, sometimes memory leaks.   Eeek!  These functions are very helpful when testing our Midas Rich Text LSX, as well as other LSXs, to ensure that memory is not leaking, but even for non-API developers, these are very helpful for determining whether Notes is not letting go of memory for one reason or another.

"So", some bright soul is sure to say, "aren't these just the constants for GetThreadInfo?"

Well, yes they are, but Lsi_info allows values that GetThreadInfo doesn't, and also works in any previous version of Notes, which GetThreadInfo doesn't either.  For these reasons, I use the Lsi_info function.

My agent
The simple agent I tend to use is below saves the agent name and three values:

LSI_Info(50) returns the LotusScript memory allocated. 
LSI_Info(51) returns the LotusScript memory allocated from the OS. 
LSI_Info(52) returns the LotusScript blocks used. 

Sub Initialize
   DimAs New NotesSession
   Dim agent As NotesAgent
   Dim db As NotesDatabase
   Dim doc As NotesDocument
   
   Set db=s.CurrentDatabase
   Set agent = s.CurrentAgent
   Set doc = New NotesDocument(db)
   doc.Form = "MemoryLog"
   doc.AgentName = agent.Name
   doc.lsMemory = Lsi_info(50)
   doc.lsMemoryOS = Lsi_info(51)
   doc.lsMemoryBlks = Lsi_info(52)
   Call doc.Save(True, True)
End Sub

My agent simply saves a document with the current values each time it is called.  You could log this instead, or simply compare one to another, but be aware that there is a lot of start up cost to some operations, and there is also a cost to any background processes running, so try this when nothing else is happening and when you control the situation as much as possible.  With LSX issues, or API issues called through LotusScript, the most important number is usually the blocks.  These represent the "handles" used to open a document or allocate a block of memory, and if this value keeps growing, you will eventually die.  The LotusScript memory tends to grow more with pure LotusScript use, and the memory allocated from the OS tells you whether you are taxing the external memory.  

My best advice is, don't sweat the details.  If any of these values keeps growing, you probably have a problem.  If the number of blocks keeps growing, make sure to do explicit deletes of objects and see if that helps.  If the blocks stay the same and memory keeps growing, watch for arrays and lists that are growing uncontrollably.

Additional undocumented codes
LSI_Info(12) Procedure name of call to current procedure (according to this post by Damien Masson)

LSI_Info(14) returns a list of the LS modules called so far. There are three parameters for each module. The first seems to be some code for the script library, the second is the module name, and the third is the last line number executed in the module before the net module was called (according to this post by Peter Presnell)

Documented codes from LSPRCVAL.LSS file
'-----------------------------------------------------------------------------
' File:      lsprcval.lss
' Copyright (c) 1997 Lotus Development Corporation
'
' Description:  Constants for use with the LSITHREADINFO builtin
'
'-----------------------------------------------------------------------------
public const LSI_THREAD_LINE=0
public const LSI_THREAD_PROC=1
public const LSI_THREAD_MODULE=2
public const LSI_THREAD_VERSION=3
public const LSI_THREAD_LANGUAGE=4
public const LSI_THREAD_COUNTRY=5
public const LSI_THREAD_TICKS=6
public const LSI_THREAD_TICKS_PER_SEC=7
public const LSI_THREAD_PROCESS_ID=8
public const LSI_THREAD_TASK_ID=9
public const LSI_THREAD_CALLPROC=10
public const LSI_THREAD_CALLMODULE=11

Copyright © 2004 Genii Software Ltd.