Windows service Vs Console app performance

O

Ollie Leahy

Hello,

We've an app that I can run as a console app or as a windows
service using the Windows services manager. I notice that it
runs much faster from the console than it does as a service.
For a certain data set the console app completes in about
20 seconds whereas the same code running as a service completes
in about 2 minutes and 20 seconds.

I've also been able repeat this behaviour with a trivial test
function. (30 seconds compared to 60 seconds)

Does anyone know whether this is recognised, that services
run more slowly than console apps? Or whether there is something
I can do, programatically, to make the service perform similarly
to the console app.

I could supply sample code of the trivial app if that would be
useful.

Thanks,
Ollie
 
J

Jon Skeet [C# MVP]

Ollie Leahy said:
We've an app that I can run as a console app or as a windows
service using the Windows services manager. I notice that it
runs much faster from the console than it does as a service.
For a certain data set the console app completes in about
20 seconds whereas the same code running as a service completes
in about 2 minutes and 20 seconds.

I've also been able repeat this behaviour with a trivial test
function. (30 seconds compared to 60 seconds)

Does anyone know whether this is recognised, that services
run more slowly than console apps? Or whether there is something
I can do, programatically, to make the service perform similarly
to the console app.

I could supply sample code of the trivial app if that would be
useful.

Yes, the trivial app would be useful.

My guess is that service threads run at a lower priority (or the whole
service process does) but that's just a guess...
 
R

Russell Hind

Jon said:
My guess is that service threads run at a lower priority (or the whole
service process does) but that's just a guess...

Still, it should only be affected then if you have other processes
running using the CPU (i.e. compiling or something). If nothing else is
running, then it shouldn't really make a difference.

Well no to the extent the OP is seeing, anyway.

Cheers

Russell
 
O

Ollie Leahy

Thanks I'll look into the priorities of the processes

Unfortunately the code is fairly long, since it has
to set up the service and all, but, here goes,
sample -d runs as a console app,
and the familiar sample -install and then
sample -start will run it as a service ...

here goes ....


#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

SERVICE_STATUS status;
SERVICE_STATUS_HANDLE statusHandle;
DWORD err = 0;
TCHAR errstr[256];
BOOL dbg = FALSE;

VOID WINAPI serviceCtrl(DWORD dwCtrlCode);
VOID WINAPI serviceMain(DWORD dwArgc, LPTSTR *lpszArgv);
VOID CmdInstallService();
VOID CmdRemoveService();
VOID CmdStartService(int argc, char **argv);
VOID CmdStopService(int argc, char **argv);
void CmdDebugService(int argc, char ** argv);
BOOL WINAPI ControlHandler ( DWORD ctrl );
LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );

char reader_buf[1024];
char * SZSERVICENAME = "A Sample Service";
char * SZAPPNAME = "tst";
char * SZSERVICEDISPLAYNAME = "A Sample Service";
char * SZDEPENDENCIES = "";

/*
*
*/
int
appMain(int ac, char * av[])
{
time_t now = 0;
int n = 0, m = 0, j = 0;
FILE * fp = NULL;
HANDLE ph;
DWORD cl;

ph = GetCurrentProcess();
cl = GetPriorityClass(ph);

now = time(NULL);
for (n = 0; n < 100000; n++ ) {
for (m = 0; m < 10000; m++) {
j = m * n;
}
}
fp = fopen("c:/sample.log", "a+");
if (fp != NULL) {
fprintf(fp, "(%d) Run time : %d\n", cl, time(NULL) - now);
} else {
printf("(%d) Run time : %d\n", cl, time(NULL) - now);
}
return EXIT_SUCCESS;
}

/*
*
*/
int
appStop(void)
{
return 0;
}

/*
* Only auto start on a non-debug build, so that during
development
* a reboot will always stop a rogue service
*/
#if defined (DEBUG)
#define SERVICE_START_OPTION SERVICE_DEMAND_START
#else
#define SERVICE_START_OPTION SERVICE_AUTO_START
#endif


/*
* One argument
* -install registers the service with the
* Service Control Manager.
* -remove Removes the service from the
* Service Control Manager.
* -start Starts the service.
* -stop Stops the service.
*/
int
main(int argc, char **argv)
{
SERVICE_TABLE_ENTRY dispatchTable[] = {
{TEXT(SZSERVICENAME),
(LPSERVICE_MAIN_FUNCTION)serviceMain},
{NULL, NULL}
};

if ((argc > 1) && ((*argv[1] == '-'))) {
if (_stricmp("-install", argv[1]) == 0) {
CmdInstallService();
} else if (_stricmp( "-remove", argv[1]) == 0) {
CmdRemoveService();
} else if (_stricmp("-start", argv[1]) == 0) {
CmdStartService(argc, argv);
} else if (_stricmp("-stop", argv[1]) == 0) {
CmdStopService(argc, argv);
} else if (_stricmp("-d", argv[1]) == 0) {
dbg = TRUE;
CmdDebugService(argc, argv);
} else {
goto dispatch;
}
return 0;
}
dispatch:
/*
* Help message when the command is run from the console.
*/
printf( "%s -install to install the service\n",
SZAPPNAME );
printf( "%s -remove to remove the service\n",
SZAPPNAME );
printf( "%s -start to start the service\n", SZAPPNAME
);
printf( "%s -stop to stop the service\n", SZAPPNAME
);
printf( "\nStartServiceCtrlDispatcher being called.\n" );
printf( "This may take several seconds. Please wait.\n" );

StartServiceCtrlDispatcher(dispatchTable);

return 0;
}

/*
*
*/
void WINAPI
serviceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
/*
* Register service control handler
*/
statusHandle = RegisterServiceCtrlHandler(TEXT(SZSERVICENAME),
serviceCtrl);
if (!statusHandle)
goto finished;

/*
* Initialise SERVICE_STATUS
*/
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
status.dwServiceSpecificExitCode = 0;
/*
* Status has to be reported to the SCM, since there is nothing
* else to do we go straight from pending to running
*/
if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
goto finished;


if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
goto finished;

appMain(dwArgc, lpszArgv);

finished:
/*
* Tell SCM service is stopping
*/
if (statusHandle)
(VOID)ReportStatusToSCMgr(SERVICE_STOPPED, err, 0);
}

/*
* This function is called by the SCM whenever
* ControlService() is called on this service.
*/
VOID WINAPI
serviceCtrl(DWORD dwCtrlCode)
{
switch(dwCtrlCode){
/*
* Stop the service.
*/
case SERVICE_CONTROL_STOP:
status.dwCurrentState = SERVICE_STOP_PENDING;
appStop();
break;
/*
* Update the service status.
*/
case SERVICE_CONTROL_INTERROGATE:
break;
}
ReportStatusToSCMgr(status.dwCurrentState, NO_ERROR, 0);
}

/*
* Sets the current status of the service and
* reports it to the Service Control Manager
*
* dwCurrentState - the state of the service
* dwWin32ExitCode - error code to report
* dwWaitHint - worst case estimate to next checkpoint
*/
BOOL
ReportStatusToSCMgr(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
{
static DWORD checkpoint = 1;
BOOL rc = TRUE;

if (dwCurrentState == SERVICE_START_PENDING)
status.dwControlsAccepted = 0;
else
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;

status.dwCurrentState = dwCurrentState;
status.dwWin32ExitCode = dwWin32ExitCode;
status.dwWaitHint = dwWaitHint;

if ((dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED))
status.dwCheckPoint = 0;
else
status.dwCheckPoint = checkpoint++;
/*
* Report the status of the service to the service
* control manager.
*/
rc = SetServiceStatus( statusHandle, &status);
return rc;
}

/*
*
*/
void
CmdInstallService()
{
SC_HANDLE srv;
SC_HANDLE svrmgr;

TCHAR path[512];

if ( GetModuleFileName( NULL, path, 512 ) == 0 ) {
printf(TEXT("Unable to install %s - %s\n"),
TEXT(SZSERVICEDISPLAYNAME),
GetLastErrorText(errstr, 256));
return;
}
printf("Install path is <%s>\n", path);
svrmgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

if (svrmgr) {
srv = CreateService(
svrmgr, // SCManager
database
TEXT(SZSERVICENAME), // name of service
TEXT(SZSERVICEDISPLAYNAME), // name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_START_OPTION, // start type
SERVICE_ERROR_NORMAL, // error control
type
path, // service's binary
NULL, // no load ordering
group
NULL, // no tag identifier
TEXT(SZDEPENDENCIES), // dependencies
NULL, // LocalSystem
account
NULL); // no password

if ( srv ) {
printf(TEXT("%s installed.\n"),
TEXT(SZSERVICEDISPLAYNAME) );
CloseServiceHandle(srv);
} else {
printf(TEXT("CreateService fail - %s\n"),
GetLastErrorText(errstr, 256));
}
CloseServiceHandle(svrmgr);
} else
printf(TEXT("OpenSCManager fail - %s\n"),

GetLastErrorText(errstr,256));
}

/*
* Stops and removes the service
*/
void
CmdRemoveService()
{
SC_HANDLE srv;
SC_HANDLE svrmgr;

svrmgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

if (svrmgr) {
srv = OpenService(svrmgr, TEXT(SZSERVICENAME),
SERVICE_ALL_ACCESS);

if (srv) {
/*
* First make sure that the service is stopped.
*/
if (ControlService(srv, SERVICE_CONTROL_STOP, &status)) {
printf(TEXT("Stopping %s."),
TEXT(SZSERVICEDISPLAYNAME));
Sleep( 1000 );

while(QueryServiceStatus(srv, &status)) {
if (status.dwCurrentState == SERVICE_STOP_PENDING) {
printf(TEXT("."));
Sleep( 1000 );
} else {
break;
}
}

if (status.dwCurrentState == SERVICE_STOPPED)
printf(TEXT("\n%s stopped.\n"),
TEXT(SZSERVICEDISPLAYNAME));
else
printf(TEXT("\n%s failed to stop.\n"),

TEXT(SZSERVICEDISPLAYNAME));

}

/*
* Now remove the service
*/
if( DeleteService(srv) )
printf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME)
);
else
printf(TEXT("DeleteService fail - %s\n"),

GetLastErrorText(errstr,256));


CloseServiceHandle(srv);
} else {
printf(TEXT("OpenService fail - %s\n"),
GetLastErrorText(errstr,256));
}

CloseServiceHandle(svrmgr);
} else
printf(TEXT("OpenSCManager fail - %s\n"),
GetLastErrorText(errstr,256));
}

/*
* Starts the service.
*/
void
CmdStartService(int argc, char ** argv)
{
SC_HANDLE srv;
SC_HANDLE svrmgr;

svrmgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

if (svrmgr) {
srv = OpenService(svrmgr,
TEXT(SZSERVICENAME),
SERVICE_ALL_ACCESS);
if (srv) {
if(StartService(srv, 0, NULL)) {
printf(TEXT("Starting %s."),
TEXT(SZSERVICEDISPLAYNAME));
Sleep(1000);

while(QueryServiceStatus(srv, &status)) {
if (status.dwCurrentState ==
SERVICE_START_PENDING) {
printf(TEXT("."));
Sleep( 1000 );
} else {
break;
}
}
if (status.dwCurrentState == SERVICE_RUNNING)
printf(TEXT("\n%s started.\n"),
TEXT(SZSERVICEDISPLAYNAME));
else
printf(TEXT("\n%s failed to start.\n"),
TEXT(SZSERVICEDISPLAYNAME));
}
CloseServiceHandle(srv);
}else
printf(TEXT("OpenService fail - %s\n"),
GetLastErrorText(errstr,256));
CloseServiceHandle(svrmgr);
} else
printf(TEXT("OpenSCManager fail - %s\n"),
GetLastErrorText(errstr,256));
}

/*
* Stops the service.
*/
void
CmdStopService(int argc, char ** argv)
{
SC_HANDLE srv;
SC_HANDLE svrmgr;

svrmgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

if (svrmgr) {
srv = OpenService(svrmgr, TEXT(SZSERVICENAME),
SERVICE_ALL_ACCESS);
if (srv) {
/*
* First make sure that the service is stopped.
*/
if (ControlService(srv, SERVICE_CONTROL_STOP, &status)) {
printf(TEXT("Stopping %s."),
TEXT(SZSERVICEDISPLAYNAME));
Sleep( 1000 );
while(QueryServiceStatus(srv, &status)) {
if (status.dwCurrentState == SERVICE_STOP_PENDING) {
printf(TEXT("."));
Sleep( 1000 );
} else {
break;
}
}
if (status.dwCurrentState == SERVICE_STOPPED)
printf(TEXT("\n%s stopped.\n"),

TEXT(SZSERVICEDISPLAYNAME));
else
printf(TEXT("\n%s failed to stop.\n"),

TEXT(SZSERVICEDISPLAYNAME));
}
CloseServiceHandle(srv);
} else
printf(TEXT("OpenService fail - %s\n"),
GetLastErrorText(errstr,256));
CloseServiceHandle(svrmgr);
} else
printf(TEXT("OpenSCManager fail - %s\n"),
GetLastErrorText(errstr,256));
}

/*
* Debugging support function,
*
* Control C or control break will stop the
* service in debug mode.
*/
BOOL WINAPI
ControlHandler ( DWORD ctrl )
{
switch( ctrl ) {
case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
printf(TEXT("Stopping %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
appStop();
return TRUE;
}
return FALSE;
}

/*
* Debug support function, run the service as
* a consol mode application.
*
* argc - number of command line arguments
* argv - array of command line arguments
*/
void
CmdDebugService(int argc, char ** argv)
{
DWORD dwArgc;
LPTSTR *lpszArgv;

#ifdef UNICODE
lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) );
#else
dwArgc = (DWORD) argc;
lpszArgv = argv;
#endif

printf(TEXT("Debugging %s.\n"), TEXT(SZSERVICEDISPLAYNAME));

SetConsoleCtrlHandler( ControlHandler, TRUE );

appMain( dwArgc, lpszArgv );
}
/*
* Copy text for error code into a string.
*/
LPTSTR
GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize )
{
DWORD rc;
LPTSTR tmp = NULL;

rc = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
GetLastError(),
LANG_NEUTRAL,
(LPTSTR)&tmp,
0,
NULL);

/*
* A truncated message is worse than none at all, so return nothing
* if the whole message does not fit.
*/
if ( !rc || ( (long)dwSize < (long)rc+14 ) ) {
lpszBuf[0] = TEXT('\0');
} else {
int n = GetLastError();
/*
* Strip cr/lf
*/
tmp[lstrlen(tmp)-2] = TEXT('\0');
printf(lpszBuf, TEXT("%s (0x%x)"), tmp, n);
}

if ( tmp )
LocalFree((HLOCAL) tmp );

return lpszBuf;
}



*** Sent via Devdex http://www.devdex.com ***
Don't just participate in USENET...get rewarded for it!
 
J

Jon Skeet [C# MVP]

Ollie Leahy said:
Thanks I'll look into the priorities of the processes

Unfortunately the code is fairly long, since it has
to set up the service and all, but, here goes,
sample -d runs as a console app,
and the familiar sample -install and then
sample -start will run it as a service ...

Hmm... I can't see anything obvious, I'm afraid. (I'm a C# person
myself, so I may well have missed something...)

I'll see whether I get the same results with a simple C# app.
 
R

Russell Hind

William said:
I know w2k+ you can set priority of system for forground programs (i.e.
your console, winapps, etc) and services to be different. Default is
higher prio for programs (which is normally better for interactive
use.) Try changing performance options in System Icon to Background and
see if that changes speed for you. See the JPG.

But as I've mentioned, this should only help if he has other processes
running using lots of CPU time, then the service will not get as much
time on the CPU.

But if the CPU is basically idle so only his service is running, then it
can have as much CPU time as it wants, bar what is needed for the OS, so
it may make a small difference if non-essential OS services are now
higher priority, but not to the extent the user is seeing.

Maybe he has another processor intensive task running at the same time?

Cheers

Russell
 
W

William Stacey [MVP]

Agree, but priority is a funny thing. Moreover VS is foreground app, any
other open windows, task bar applets, mouse, etc. It adds up. I would
still suspect this is the issue. Easy to test. Ollie, have you tested this
yet? Please post back.
 
O

ollie

Thanks for all the replies, they have been useful,
there WAS another process running that was soaking
up a lot of CPU. I was running a VNC service to
get remote access to the machine.

So I'm putting the behaviour down to the assumption
that the timeslots for services are being limited in
some way that is allowing more cpu time for interactive
processes.

I've been able to verify that by going down to the
computer room, stopping VNC and re running my service
performance improves dramatically.

Thanks again for all help!!!

Ollie



*** Sent via Devdex http://www.devdex.com ***
Don't just participate in USENET...get rewarded for it!
 
W

William Stacey [MVP]

Thanks for the update. Cheers!

--
William Stacey, MVP

ollie said:
Thanks for all the replies, they have been useful,
there WAS another process running that was soaking
up a lot of CPU. I was running a VNC service to
get remote access to the machine.
....
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top