/*++

Copyright (c) 1998-2001 Microsoft Corporation

Module Name:

    uri.c

Abstract:

    Dumps URI Cache structures.

Author:

    Michael Courage (mcourage) 19-May-1999

Environment:

    User Mode.

Revision History:

--*/


#include "precomp.h"
#include "..\drv\hashfn.h"
#include "..\drv\hashp.h"


//
// Private prototypes.
//


//
// Public functions.
//

DECLARE_API( uriglob )

/*++

Routine Description:

    Dumps global URI Cache structures.

Arguments:

    None.

Return Value:

    None.

--*/

{
    ULONG_PTR           address = 0;
    BOOL                Enabled = FALSE;
    UL_URI_CACHE_CONFIG config;
    UL_URI_CACHE_STATS  stats;
//  UL_URI_CACHE_TABLE  table;

    ULONG_PTR           dataAddress;
    UL_NONPAGED_DATA    data;
    BOOL                gotData = FALSE;
    CHAR                uriCacheResource[MAX_RESOURCE_STATE_LENGTH];
    CHAR                uriZombieResource[MAX_RESOURCE_STATE_LENGTH];

    SNAPSHOT_EXTENSION_DATA();

    //
    // Dump cache configuration.
    //
    address = GetExpression( "&http!g_UriCacheConfig" );
    if (address) {
        if (ReadMemory(
                address,
                &config,
                sizeof(config),
                NULL
                ))
        {
            dprintf(
                "UL_URI_CACHE_CONFIG   @ %p:\n"
                "    EnableCache           = %d\n"
                "    MaxCacheUriCount      = %d\n"
                "    MaxCacheMegabyteCount = %d\n"
                "    ScavengerPeriod       = %d\n"
                "    MaxUriBytes           = %d\n"
                "    HashTableBits         = %d\n",
                address,
                config.EnableCache,
                config.MaxCacheUriCount,
                config.MaxCacheMegabyteCount,
                config.ScavengerPeriod,
                config.MaxUriBytes,
                config.HashTableBits
                );

            Enabled = config.EnableCache;

        } else {
            dprintf(
                "glob: cannot read memory for http!g_UriCacheConfig @ %p\n",
                address
                );
        }

    } else {
        dprintf(
            "uriglob: cannot find symbol for http!g_UriCacheConfig\n"
            );
    }

    if (!Enabled) {
        //
        // no point in going on..
        //
        return;
    }

    //
    // Dump Cache Statistics
    //
    address = GetExpression( "&http!g_UriCacheStats" );
    if (address) {
        if (ReadMemory(
                address,
                &stats,
                sizeof(stats),
                NULL
                ))
        {
            dprintf(
                "\n"
                "UL_URI_CACHE_STATS         @ %p:\n"
                "    UriCount               = %d\n"
                "    UriCountMax            = %d\n"
                "    UriAddedTotal          = %I64d\n"
                "    ByteCount              = %I64d\n"
                "    ByteCountMax           = %I64d\n"
                "    ZombieCount            = %d\n"
                "    ZombieCountMax         = %d\n"
                "    HitCount               = %d\n"
                "    MissTableCount         = %d\n"
                "    MissPrecondtionCount   = %d\n"
                "    MissConfigCount        = %d\n"
                "\n",
                address,
                stats.UriCount,
                stats.UriCountMax,
                stats.UriAddedTotal,
                stats.ByteCount,
                stats.ByteCountMax,
                stats.ZombieCount,
                stats.ZombieCountMax,
                stats.HitCount,
                stats.MissTableCount,
                stats.MissPreconditionCount,
                stats.MissConfigCount
                );

        } else {
            dprintf(
                "glob: cannot read memory for http!g_UriCacheStats @ %p\n",
                address
                );
        }

    } else {
        dprintf(
            "uriglob: cannot find symbol for http!g_UriCacheStats\n"
            );
    }

    //
    // Read in resource info from non-paged data
    //
    address = GetExpression( "&http!g_pUlNonpagedData" );
    if (address) {
        if (ReadMemory(
                address,
                &dataAddress,
                sizeof(dataAddress),
                NULL
                ))
        {
            if (ReadMemory(
                    dataAddress,
                    &data,
                    sizeof(data),
                    NULL
                    ))
            {
                gotData = TRUE;
            } else {
                dprintf(
                    "uriglob: cannot read memory for http!g_pUlNonpagedData = %p\n",
                    dataAddress
                    );
            }
        } else {
            dprintf(
                "uriglob: cannot read memory for http!g_pUlNonpagedData @ %p\n",
                address
                );
        }
    } else {
        dprintf(
            "uriglob: cannot find symbol for http!g_pUlNonpagedData\n"
            );
    }

#if 0
// BUGBUG: GeorgeRe must fix
    //
    // Dump table info.
    //
    if (gotData) {
        dprintf(
            "UriCacheResource      @ %p (%s)\n",
            REMOTE_OFFSET( dataAddress, UL_NONPAGED_DATA, UriCacheResource ),
            BuildResourceState( &data.UriCacheResource, uriCacheResource )
            );
    }

    address = GetExpression("&http!g_pUriCacheTable");
    if (address) {
        if (ReadMemory(
                address,
                &dataAddress,
                sizeof(dataAddress),
                NULL
                ))
        {
            if (ReadMemory(
                    dataAddress,
                    &table,
                    sizeof(table),
                    NULL
                    ))
            {
                dprintf(
                    "UL_URI_CACHE_TABLE    @ %p:\n"
                    "    UriCount          = %d\n"
                    "    ByteCount         = %d\n"
                    "    BucketCount       = %d\n"
                    "    Buckets           @ %p\n"
                    "\n",
                    dataAddress,
                    table.UriCount,
                    table.ByteCount,
                    table.BucketCount,
                    REMOTE_OFFSET( dataAddress, UL_URI_CACHE_TABLE, Buckets )
                    );

            } else {
                dprintf(
                    "uriglob: cannot read memory for http!g_pUriCacheTable = %p\n",
                    dataAddress
                    );
            }
        } else {
            dprintf(
                "uriglob: cannot read memory for http!g_pUriCacheTable @ %p\n",
                address
                );
        }
    } else {
        dprintf(
            "uriglob: cannot find symbol for http!g_pUriCacheTable\n"
            );
    }
#endif

    //
    // Dump Zombie list info.
    //
    if (gotData) {
        dprintf(
            "UriZombieResource     @ %p (%s)\n",
            REMOTE_OFFSET( dataAddress, UL_NONPAGED_DATA, UriZombieResource ),
            BuildResourceState( &data.UriZombieResource, uriZombieResource )
            );
    }

    dprintf(
        "g_ZombieListHead      @ %p\n"
        "\n",
        GetExpression("&http!g_ZombieListHead")
        );

    //
    // Dump reftrace info
    //
    address = GetExpression("&http!g_UriTraceLog");
    if (address) {
        if (ReadMemory(
                address,
                &dataAddress,
                sizeof(dataAddress),
                NULL
                ))
        {
            dprintf(
                "UL_URI_CACHE_ENTRY ref log: "
                "!ulkd.ref %x\n"
                "\n",
                dataAddress
                );
        }
    }

}   // uriglob


DECLARE_API( uri )

/*++

Routine Description:

    Dumps a UL_URI_CACHE_ENTRY structure.

Arguments:

    Address of structure

Return Value:

    None.

--*/
{
    ULONG_PTR address = 0;
    CHAR  star = 0;
    ULONG result;
    UL_URI_CACHE_ENTRY urientry;

    dprintf("BUGBUG: GeorgeRe needs to fix DumpAllUriEntries!\n");

#if 0
    SNAPSHOT_EXTENSION_DATA();

    //
    // Snag the address from the command line.
    //

    address = GetExpression( args );

    if (address == 0)
    {
        sscanf( args, "%c", &star );

        if (star == '*') {
            DumpAllUriEntries();
        } else {
            PrintUsage( "uri" );
        }
        return;
    }

    //
    // Read the request header.
    //

    if (!ReadMemory(
            address,
            &urientry,
            sizeof(urientry),
            &result
            ))
    {
        dprintf(
            "uri: cannot read UL_URI_CACHE_ENTRY @ %p\n",
            address
            );
        return;
    }

    //
    // Dump it.
    //

    DumpUriEntry(
        "",
        "uri: ",
        address,
        &urientry
        );
#endif
}   // uri

VOID
AnalysisHashTable(
    IN ULONG_PTR RemoteAddress,
    IN ULONG     TableSize,
    IN ULONG     CacheLineSize
    )
{
    ULONG_PTR   address = 0;
    HASHBUCKET  bucket;
    ULONG       i;
    ULONG       max, min, zeros, total;
    FLOAT       avg, avg_nonzero;
    ULONG       result;

    max = 0;
    min =  ULONG_MAX;
    total = 0;
    zeros = 0;
    
    for (i = 0; i < TableSize; i++) 
    {

        address = (ULONG_PTR)(RemoteAddress + (i * CacheLineSize));

        if (!ReadMemory(
                address,
                &bucket,
                sizeof(bucket),
                &result
                ))
        {
            dprintf(
                "cannot read HASHBUCKET @ %p, i = %d\n",
                address,
                i
                );
            
            break;

        }
        
        total += (ULONG) bucket.Entries;
        
        if (bucket.Entries > max) 
        {
            max = (ULONG) bucket.Entries;
        }
        
        if (bucket.Entries < min)
        {
            min = (ULONG) bucket.Entries;
        }
        
        if (bucket.Entries == 0)
        {
            ++zeros;
        }
    }

    avg = (FLOAT)total / (FLOAT)i;
    avg_nonzero = (FLOAT)total / (FLOAT)(i - zeros);

    dprintf(
          "Total Entries  = %d:\n"
          "MAX Entries in a bucket  = %d:\n"
          "MIN Entries in a bucket  = %d:\n"
          "AVG Entries in a bucket  = %f:\n"
          "ZERO buckets  = %d:\n"
          "AVG NONZERO Entries in a bucket  = %f:\n",
          total,
          max,
          min,
          avg,
          zeros,
          avg_nonzero
          );
} // AnalysisHashTable


DECLARE_API( urihash )

/*++

Routine Description:

    Dumps URI Cache Hash Table structures.

Arguments:

    None.

Return Value:

    None.

--*/

{
    ULONG_PTR           address = 0;
    ULONG_PTR           address2 = 0;
    ULONG_PTR           address3 = 0;
    HASHTABLE           table;
    ULONG               tablesize;
    ULONG               cachelinesize;
    
    SNAPSHOT_EXTENSION_DATA();

    //
    // Dump cache configuration.
    //
    address = GetExpression( "&http!g_UriCacheTable" );
    if (address) 
    {
        if (ReadMemory(
                address,
                &table,
                sizeof(table),
                NULL
                ))
        {
            dprintf(
                "HASHTABLE   @ %p:\n"
                "    Signature           = %d\n"
                "    PoolType      = %d\n"
                "    NumberOfBytes      = %d\n"
                "    pAllocMem = %p\n"
                "    pBuckets           = %p\n",
                address,
                table.Signature,
                table.PoolType,
                table.NumberOfBytes,
                table.pAllocMem,
                table.pBuckets
                );

            address2 = GetExpression( "&http!g_UlHashTableSize" );

            if (address2) 
            {
                if (ReadMemory(
                                address2,
                                &tablesize,
                                sizeof(tablesize),
                                NULL
                               ))
                {
                    address3 = GetExpression( "&http!g_UlCacheLineSize" );

                    if (address3) 
                    {
                        if (ReadMemory(
                                        address3,
                                        &cachelinesize,
                                        sizeof(cachelinesize),
                                        NULL
                                        ))
                        {
                            AnalysisHashTable((ULONG_PTR)table.pBuckets, tablesize, cachelinesize);
                        } 
                        else 
                        {

                            dprintf(
                                    "urihash: cannot read memory for http!g_UlCacheLineSize @ %p\n",
                                    address3
                                   );
                        }
                    } 
                    else 
                    {
                        dprintf(
                                "urihash: cannot find symbol for http!g_UlCacheLineSize\n"
                               );
                    }
                } 
                else 
                {
                    dprintf(
                            "urihash: cannot read memory for http!g_UlHashTableSize @ %p\n",
                            address2
                            );
                }

            } 
            else 
            {
                dprintf(
                        "urihash: cannot find symbol for http!g_UlHashTableSize\n"
                        );
            }

        }
        else 
        {
            dprintf(
                "urihash: cannot read memory for http!g_UriCacheTable @ %p\n",
                address
                );
        }

    }
    else 
    {
        dprintf(
            "urihash: cannot find symbol for http!g_UriCacheTable\n"
            );
    }

}   // urihash