Novell is now a part of Micro Focus

Load Testing a NetWare 5.1 Server

Articles and Tips: article

Steve Ulinski
Sr. Program Systems Analyst
Rush Presbyterian St. Luke's Medical Center
sulinski@rush.edu

01 Oct 2002


We needed to run a load test on a NetWare 5.1 server, simulating a large number of users connected to the server. The requirements set by the engineers were to have as many users logged in as possible, using files and leaving them open. There also needed to be at least 30% utilization, good traffic, and use of the dirty cache buffers.

After researching several Load Testing software packages, we discovered that there was no software package available to provide us with the type of load testing we desired. Because of this, we began to look into alternative options in order to perform a reasonable load test of the server.

Since we were new to NetWare programming, the discovery of NetBasic was an epiphany to the project. After looking at the documentation, we concluded that it would be possible to write a script in NetBasic that would simulate as many users as needed. The final code allowed us to simulate 1,000 users logged in, and we were able to actually provide a heavier load than what is currently on our production systems.

The NetBasic program we wrote consisted of two parts. The first part was a loader program that created users and spawned a second program. Once the second program was spawned, it would simulate the users logging into the tree, processing files, and generating network traffic. Here is the code for our first NetBasic program.

SRVLOAD.BAS
To Run: SRVLOAD <#of USERS> <#of Days to Run>
   
Sub Main
' Number of user to create
RunCount = Data:INTEGER (SYS:Param(2))
   
' Number of Hours to run each spawned user
RunTime = Data:String (SYS:Param(3))
   
' Login as an admin
NDS:Session:Login("admin", "pasword"); ' Change this line for your Tree
   
' Change CX to CX for user creation
NDS:CONTEXT:PATH:CHANGE("Users.rpslmc"); ' Change this line for your Tree
   
' Sets X to 0
x=0
   
' Do creates user and spawns additional programs to run as user
Do While (true)
   
   ' Exits the program on demand by creating an END.NOW 
      ' file in the directory
   EHandle = FIO:OPEN("Vol1:\File\END.NOW", "r")
   If (ERR = 0);
      Quit;
   EndIf
   ' sets the amount of users to create, once the amount 
      ' is reached the program quits
   If (x = RunCount)
      Out = NDS:Session:Logout;
      Exit;
   EndIf
   
   ' Generates a random number for user creation 
   ' Random number creates minor security since 
      ' no password will associated with user
   UserN = Data:String(Math:Random * 10)
   
   ' Creates the user ID
   Success=NDS:ADD:User(UserN,UserN)
   If (Success)
      x = x + 1
   
      ' Copies the NetBasic Program runuser.bas to random(USER) number
      ' And runs the program as the user.
      If Dir:File:Copy ("SYS:\Program\runuser.bas","SYS:\Program\Users\" +
         UserN +".bas")
         RunP = "SYS:\Program\Users\" + UserN + ".bas"
         Spawn = SYS:Call ("Run.nlm "+ RunP + " " + UserN + " " +
            RunTime + " " + Data:String(x));
      Else
         Quit:
      EndIf
   EndIf
EndDo
   
End Sub
&_;&_;&_;&_;&_;&_;&_;&_;&_;&_;&_;___

The second program goes as follows:

RUNUSER.BAS 
Runuser.bas is auto loaded by the srvload.bas.
   
Sub Main
' Sets user name passed from SRVLOAD.BAS 
CUser= Data:String (SYS:Param(2))
   
' Sets the length of days the program is to run passed from SRVLOAD.BAS
LTime= Data:Integer (SYS:Param(3))
   
' Sets the current spawned number passed from SRVLOAD.BAS
Spawn = Data:String (SYS:Param(4))
   
' Sets fOpen counter
Count = 0
   
' Sets FTPCount counter for naming FTP'd file
FTPCount = 0
   
' Login as user
NDS:Session:Login (".CN=" + cuser + ".OU=USERS.O=RPSLMC", ""); 
      'Change this for your TREE
   
' Sets the length of time to run in days
SecondsInWeek = ltime*24*60*60
ServerDateObj = NET:Server:Date:Get
Date = ServerDateObj.Date
Time = ServerDateObj.Time
NextWeek = DATE:UTF (Date, Time) + SecondsInWeek
DateObj = DATE:Object(NextWeek)
   
' Changes Dir to VOL1:\Files makes new Dir as User and switches to it, 
      'If fails, Quits app
If (Dir:Change ("VOL1:\File"))
   Dir:Make (cuser)
   Dir:Change (Cuser)
   UserDir = DIR:Current
Else
   Quit
EndIf
   
x=0
   
' Runs until the amount of time passes that is passed from the command line
Do While (True)
   ' Checks time and compares to start time. 
   ' If suffcient time passes exits the loop
   ServerDateObj2 = NET:Server:Date:Get
   ' Looks for a file called END.NOW in the VOL1:File dir. 
   ' If the file exsists program exits the loop
   EHandle = FIO:OPEN("Vol1:\File\END.NOW", "r")
   
   If ((ServerDateObj2.date >= DateObj.date) & (ServerDateObj2.Time >=
      DateObj.Time)|(ERR = 0));
   
      ' Closes any open files
      Count = Count - 1 
      Do While (True)
         If (Count <= 0)
            Quit
         EndIf
         FIO:Close(fOpen(Count))
         Count = Count - 1
      EndDo
      Out = NDS:Session:Logout
      Quit;
   EndIf
   
   ' Random generatated number to run new process as the user
   DoIt = 0  
   DoIt = ((Math:Random * 10 ) / 32767)
   
   ' Writes user's current status on screen
   
   WIN:AT (1,1);
   WIN:SAY ("Current User: " + CUser + " Spawn Number:" + Spawn);
   
   ' Makes Files
   ' Will open the total amount you specify, will allow for 26 
      ' files for each user.
   If (((DoIt = 4) | (DoIt = 5) | (DoIt = 6) | (DoIt = 7) | 
      (DoIt = 8)) & (Count <= 26))

   
      WIN:AT (2,1);
      WIN:SAY ("Opening File " + Data:String(DoIT) + " " +
         Data:String(ServerDateObj2.Time) + "  " +
            Data:String(Count) 
            +"             ")      Mode = "w+"+"t"
      Handle = FIO:Open (Data:String(Math:Random * 10) + ".tst", Mode)
   
      If (ERR = 0)
         fOpen(Count) = Handle
         FIO:Write (Handle, "TestString1", "TestString2")
         Count = Count + 1
      EndIf
   EndIf
' Close File
   If (((DoIt = 2) | (DoIt = 3)) & (Count > 0))
      WIN:AT (2,1);
      WIN:SAY ("Closing File " + Data:String(DoIT) + " " +
         Data:String(ServerDateObj2.Time) + "           ")
   
      If (Count > 0)
         cCount = Count - 1
   
         If (FIO:Close (fOpen(cCount)))
            Count = Count - 1
            WIN:AT (2,1);
            WIN:SAY ("Closing File " + Data:String(DoIT) + " " +
               Data:String(ServerDateObj2.Time) + " Success")
         EndIf 
      EndIf
   EndIf
   
   ' Copy a file
   If (DoIt = 1)
      WIN:AT (2,1);
      WIN:SAY ("Copy File " + Data:String(DoIT) + " " +
         Data:String(ServerDateObj2.Time))
      DIR:FILE:COPY ("sys:\Program\copy.pdf",  UserDir + "\" + 
         Data:String(FTPCount) + Cuser + ".pdf")
   EndIf
   
   ' Deletes Files
   If (DoIt = 0)
      WIN:AT (2,1);
      WIN:SAY ("Deleting File " + Data:String(DoIT) + " " +
         Data:String(ServerDateObj2.Time) + "         ")
      fobj = Dir:First ("*.*", 0 )
      fCount = 1
   
      Do while (fobj.error = 0)
         fCount = fCount + 1
         fobj = Dir:Next (fobj)
      EndDo
   
      CFile = 1
      fobj = Dir:First ("*.*", 0 )
      KFile = ((Math:Random * fcount) /32767 )
   
      Do While (CFile < fCount)
         If (kFile = cFile)
            Dir:File:Delete (fobj.name + "." + fobj.extension)
         EndIf
         fobj = Dir:Next (fobj)
         CFile = CFile + 1
      EndDo
   
   EndIf
   
   FTPCount = FTPCount + 1
   
   ' Generates light traffic
   FTP:Verbose (0)
   FTP:Login ("ftp.Novell.Com","anonymous", "me@email.com"); 
' Above line needs to be modified
   FTP:CD ("pub"); 'You may need to modify this line
   FTP:Logout
   
   WIN:AT (3,1);
   WIN:SAY ("Open File Count :" + Data:String(Count) + "    ")

EndDo
End sub

Note: When we used this program to run our simulations, we needed to modify several set commands in order to keep the system from crashing, such as:

Note: Set Maximum File Locks = 75000 Set Minimum Directory Cache Buffers = 2000 Set Maximum Directory Cache Buffers = 4000 Set Maximum Concurrent Directory Cache Writes = 500

Conclusion

It is critical to take into account that each simulated user is running an instance of RUN.NLM. Because of the amount of activity generated on the server during the debugging and testing of these programs, we often crashed the server while performing things like using the Remote Console. The FILESYS.NLM constantly ran out of memory and certain screens in Monitor also crashed the server. We determined that these crashes were not due to faults in our two programs, however. The programs are solid; you just need to experiment with the number of users and open files for your particular test system to achieve a workable test environment.

* Originally published in Novell AppNotes


Disclaimer

The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.

© Copyright Micro Focus or one of its affiliates