diff --git a/ar/AdaptiveArithmeticCompress.cs b/ar/AdaptiveArithmeticCompress.cs
deleted file mode 100644
index f5f22f7..0000000
--- a/ar/AdaptiveArithmeticCompress.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using System;
-using System.IO;
-
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-
-///
-/// Compression application using adaptive arithmetic coding.
-/// Usage: java AdaptiveArithmeticCompress InputFile OutputFile
-/// Then use the corresponding "AdaptiveArithmeticDecompress" application to recreate the original input file.
-/// Note that the application starts with a flat frequency table of 257 symbols (all set to a frequency of 1),
-/// and updates it after each byte encoded. The corresponding decompressor program also starts with a flat
-/// frequency table and updates it after each byte decoded. It is by design that the compressor and
-/// decompressor have synchronized states, so that the data can be decompressed properly.
-///
-public class AdaptiveArithmeticCompress
-{
-
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
- public static void Main( string[] args )
- {
- /* @@@@ PORT
- // Handle command line arguments
- if (args.Length != 2)
- {
- Console.Error.WriteLine("Usage: java AdaptiveArithmeticCompress InputFile OutputFile");
- Environment.Exit(1);
- return;
- }
- File inputFile = new File(args[0]);
- File outputFile = new File(args[1]);
-
- // Perform file compression
- using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
- {
- compress(@in, @out);
- }
- */
- }
-
-
- // To allow unit testing, this method is package-private instead of private.
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException
- internal static void compress( Stream @in, BitOutputStream @out )
- {
- FlatFrequencyTable initFreqs = new FlatFrequencyTable( 257 );
- FrequencyTable freqs = new SimpleFrequencyTable( initFreqs );
- ArithmeticEncoder enc = new ArithmeticEncoder( 32, @out );
- while( true )
- {
- // Read and encode one byte
- int symbol = @in.ReadByte();
- if( symbol == -1 )
- {
- break;
- }
- enc.write( freqs, symbol );
- freqs.increment( symbol );
- }
- enc.write( freqs, 256 ); // EOF
- enc.finish(); // Flush remaining code bits
- }
-
-}
diff --git a/ar/AdaptiveArithmeticDecompress.cs b/ar/AdaptiveArithmeticDecompress.cs
deleted file mode 100644
index 6f8837f..0000000
--- a/ar/AdaptiveArithmeticDecompress.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using System;
-using System.IO;
-
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-
-///
-/// Decompression application using adaptive arithmetic coding.
-/// Usage: java AdaptiveArithmeticDecompress InputFile OutputFile
-/// This decompresses files generated by the "AdaptiveArithmeticCompress" application.
-///
-public class AdaptiveArithmeticDecompress
-{
-
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
- public static void Main( string[] args )
- {
- /* @@@@ PORT
- // Handle command line arguments
- if (args.Length != 2)
- {
- Console.Error.WriteLine("Usage: java AdaptiveArithmeticDecompress InputFile OutputFile");
- Environment.Exit(1);
- return;
- }
- File inputFile = new File(args[0]);
- File outputFile = new File(args[1]);
-
- // Perform file decompression
- using (BitInputStream @in = new BitInputStream(new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read))), Stream @out = new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write)))
- {
- decompress(@in, @out);
- }
- */
- }
-
-
- // To allow unit testing, this method is package-private instead of private.
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException
- internal static void decompress( BitInputStream @in, Stream @out )
- {
- FlatFrequencyTable initFreqs = new FlatFrequencyTable( 257 );
- FrequencyTable freqs = new SimpleFrequencyTable( initFreqs );
- ArithmeticDecoder dec = new ArithmeticDecoder( 32, @in );
- while( true )
- {
- // Decode and write one byte
- int symbol = dec.read( freqs );
- if( symbol == 256 ) // EOF symbol
- {
- break;
- }
- @out.WriteByte( (byte)symbol );
- freqs.increment( symbol );
- }
- }
-
-}
diff --git a/ar/ArithmeticCoderBase.cs b/ar/ArithmeticCoderBase.cs
deleted file mode 100644
index 4c68a68..0000000
--- a/ar/ArithmeticCoderBase.cs
+++ /dev/null
@@ -1,185 +0,0 @@
-using System;
-using System.Diagnostics;
-
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-///
-/// Provides the state and behaviors that arithmetic coding encoders and decoders share.
-///
-///
-public abstract class ArithmeticCoderBase
-{
-
- /*---- Configuration fields ----*/
-
- ///
- /// Number of bits for the 'low' and 'high' state variables. Must be in the range [1, 62].
- ///
- /// For state sizes less than the midpoint of around 32, larger values are generally better -
- /// they allow a larger maximum frequency total (maximumTotal), and they reduce the approximation
- /// error inherent in adapting fractions to integers; both effects reduce the data encoding loss
- /// and asymptotically approach the efficiency of arithmetic coding using exact fractions.
- /// But for state sizes greater than the midpoint, because intermediate computations are limited
- /// to the long integer type's 63-bit unsigned precision, larger state sizes will decrease the
- /// maximum frequency total, which might constrain the user-supplied probability model.
- /// Therefore numStateBits=32 is recommended as the most versatile setting
- /// because it maximizes maximumTotal (which ends up being slightly over 2^30).
- /// Note that numStateBits=62 is legal but useless because it implies maximumTotal=1,
- /// which means a frequency table can only support one symbol with non-zero frequency.
- ///
- ///
- protected internal readonly int numStateBits;
-
- ///
- /// Maximum range (high+1-low) during coding (trivial), which is 2^numStateBits = 1000...000.
- protected internal readonly long fullRange;
-
- ///
- /// The top bit at width numStateBits, which is 0100...000.
- protected internal readonly long halfRange;
-
- ///
- /// The second highest bit at width numStateBits, which is 0010...000. This is zero when numStateBits=1.
- protected internal readonly long quarterRange;
-
- ///
- /// Minimum range (high+1-low) during coding (non-trivial), which is 0010...010.
- protected internal readonly long minimumRange;
-
- ///
- /// Maximum allowed total from a frequency table at all times during coding.
- protected internal readonly long maximumTotal;
-
- ///
- /// Bit mask of numStateBits ones, which is 0111...111.
- protected internal readonly long stateMask;
-
-
-
- /*---- State fields ----*/
-
- ///
- /// Low end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 0s.
- ///
- protected internal long low;
-
- ///
- /// High end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 1s.
- ///
- protected internal long high;
-
-
-
- /*---- Constructor ----*/
-
- ///
- /// Constructs an arithmetic coder, which initializes the code range.
- /// the number of bits for the arithmetic coding range
- /// if stateSize is outside the range [1, 62]
- public ArithmeticCoderBase( int numBits )
- {
- if( numBits < 1 || numBits > 62 )
- {
- throw new System.ArgumentException( "State size out of range" );
- }
- numStateBits = numBits;
- fullRange = 1L << numStateBits;
- halfRange = (long)( (ulong)fullRange >> 1 ); // Non-zero
- quarterRange = (long)( (ulong)halfRange >> 1 ); // Can be zero
- minimumRange = quarterRange + 2; // At least 2
- maximumTotal = Math.Min( long.MaxValue / fullRange, minimumRange );
- stateMask = fullRange - 1;
-
- low = 0;
- high = stateMask;
- }
-
-
-
- /*---- Methods ----*/
-
- ///
- /// Updates the code range (low and high) of this arithmetic coder as a result
- /// of processing the specified symbol with the specified frequency table.
- /// Invariants that are true before and after encoding/decoding each symbol
- /// (letting fullRange = 2numStateBits ):
- ///
- /// 0 ≤ low ≤ code ≤ high < fullRange. ('code' exists only in the decoder.)
- /// Therefore these variables are unsigned integers of numStateBits bits.
- /// low < 1/2 × fullRange ≤ high.
- /// In other words, they are in different halves of the full range.
- /// (low < 1/4 × fullRange) || (high ≥ 3/4 × fullRange).
- /// In other words, they are not both in the middle two quarters.
- /// Let range = high − low + 1, then fullRange/4 < minimumRange ≤ range ≤
- /// fullRange. These invariants for 'range' essentially dictate the maximum total that the
- /// incoming frequency table can have, such that intermediate calculations don't overflow.
- ///
- /// the frequency table to use
- /// the symbol that was processed
- /// if the symbol has zero frequency or the frequency table's total is too large
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: protected void update(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException
- protected internal virtual void update( CheckedFrequencyTable freqs, int symbol )
- {
- // State check
- Debug.Assert( low >= high || ( low & stateMask ) != low || ( high & stateMask ) != high, "Low or high out of range" );
-
- long range = high - low + 1;
- Debug.Assert( range < minimumRange || range > fullRange, "Range out of range" );
-
- // Frequency table values check
- long total = freqs.Total;
- long symLow = freqs.getLow( symbol );
- long symHigh = freqs.getHigh( symbol );
- Debug.Assert( symLow == symHigh, "Symbol has zero frequency" );
-
- Debug.Assert( total > maximumTotal, "Cannot code symbol because total is too large" );
-
- // Update range
- long newLow = low + symLow * range / total;
- long newHigh = low + symHigh * range / total - 1;
- low = newLow;
- high = newHigh;
-
- // While low and high have the same top bit value, shift them out
- while( ( ( low ^ high ) & halfRange ) == 0 )
- {
- shift();
- low = ( ( low << 1 ) & stateMask );
- high = ( ( high << 1 ) & stateMask ) | 1;
- }
- // Now low's top bit must be 0 and high's top bit must be 1
-
- // While low's top two bits are 01 and high's are 10, delete the second highest bit of both
- while( ( low & ~high & quarterRange ) != 0 )
- {
- underflow();
- low = ( low << 1 ) ^ halfRange;
- high = ( ( high ^ halfRange ) << 1 ) | halfRange | 1;
- }
- }
-
-
- ///
- /// Called to handle the situation when the top bit of {@code low} and {@code high} are equal.
- /// if an I/O exception occurred
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: protected abstract void shift() throws java.io.IOException;
- protected internal abstract void shift();
-
-
- ///
- /// Called to handle the situation when low=01(...) and high=10(...).
- /// if an I/O exception occurred
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: protected abstract void underflow() throws java.io.IOException;
- protected internal abstract void underflow();
-
-}
diff --git a/ar/ArithmeticCompress.cs b/ar/ArithmeticCompress.cs
deleted file mode 100644
index bd73f67..0000000
--- a/ar/ArithmeticCompress.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-using System;
-using System.IO;
-
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-
-///
-/// Compression application using static arithmetic coding.
-/// Usage: java ArithmeticCompress InputFile OutputFile
-/// Then use the corresponding "ArithmeticDecompress" application to recreate the original input file.
-/// Note that the application uses an alphabet of 257 symbols - 256 symbols for the byte
-/// values and 1 symbol for the EOF marker. The compressed file format starts with a list
-/// of 256 symbol frequencies, and then followed by the arithmetic-coded data.
-///
-public class ArithmeticCompress
-{
-
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
- public static void Main( string[] args )
- {
- /* @@ PORT
- // Handle command line arguments
- if (args.Length != 2)
- {
- Console.Error.WriteLine("Usage: java ArithmeticCompress InputFile OutputFile");
- Environment.Exit(1);
- return;
- }
- File inputFile = new File(args[0]);
- File outputFile = new File(args[1]);
-
- // Read input file once to compute symbol frequencies
- FrequencyTable freqs = getFrequencies(inputFile);
- freqs.increment(256); // EOF symbol gets a frequency of 1
-
- // Read input file again, compress with arithmetic coding, and write output file
- using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
- {
- writeFrequencies(@out, freqs);
- compress(freqs, @in, @out);
- }
- */
- }
-
-
- // Returns a frequency table based on the bytes in the given file.
- // Also contains an extra entry for symbol 256, whose frequency is set to 0.
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: private static FrequencyTable getFrequencies(java.io.File file) throws java.io.IOException
- private static FrequencyTable getFrequencies( string file )
- {
-
-
- FrequencyTable freqs = new SimpleFrequencyTable( new int[257] );
- using( Stream input = new BufferedStream( new FileStream( file, FileMode.Open, FileAccess.Read ) ) )
- {
- while( true )
- {
- int b = input.ReadByte();
- if( b == -1 )
- {
- break;
- }
- freqs.increment( b );
- }
- }
- return freqs;
- }
-
-
- // To allow unit testing, this method is package-private instead of private.
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: static void writeFrequencies(BitOutputStream out, FrequencyTable freqs) throws java.io.IOException
- internal static void writeFrequencies( BitOutputStream @out, FrequencyTable freqs )
- {
- for( int i = 0; i < 256; i++ )
- {
- writeInt( @out, 32, freqs.get( i ) );
- }
- }
-
-
- // To allow unit testing, this method is package-private instead of private.
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: static void compress(FrequencyTable freqs, java.io.InputStream in, BitOutputStream out) throws java.io.IOException
- internal static void compress( FrequencyTable freqs, Stream @in, BitOutputStream @out )
- {
- ArithmeticEncoder enc = new ArithmeticEncoder( 32, @out );
- while( true )
- {
- int symbol = @in.ReadByte();
- if( symbol == -1 )
- {
- break;
- }
- enc.write( freqs, symbol );
- }
- enc.write( freqs, 256 ); // EOF
- enc.finish(); // Flush remaining code bits
- }
-
-
- // Writes an unsigned integer of the given bit width to the given stream.
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: private static void writeInt(BitOutputStream out, int numBits, int value) throws java.io.IOException
- private static void writeInt( BitOutputStream @out, int numBits, int value )
- {
- if( numBits < 0 || numBits > 32 )
- {
- throw new System.ArgumentException();
- }
-
- for( int i = numBits - 1; i >= 0; i-- )
- {
- @out.write( ( (int)( (uint)value >> i ) ) & 1 ); // Big endian
- }
- }
-
-}
diff --git a/ar/ArithmeticDecoder.cs b/ar/ArithmeticDecoder.cs
deleted file mode 100644
index 55809e6..0000000
--- a/ar/ArithmeticDecoder.cs
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-
-using System.Diagnostics;
-///
-/// Reads from an arithmetic-coded bit stream and decodes symbols. Not thread-safe.
-///
-public sealed class ArithmeticDecoder : ArithmeticCoderBase
-{
-
- /*---- Fields ----*/
-
- // The underlying bit input stream (not null).
- private BitInputStream input;
-
- // The current raw code bits being buffered, which is always in the range [low, high].
- private long code;
-
-
-
- /*---- Constructor ----*/
-
- ///
- /// Constructs an arithmetic coding decoder based on the
- /// specified bit input stream, and fills the code bits.
- /// the number of bits for the arithmetic coding range
- /// the bit input stream to read from
- /// if the input steam is {@code null}
- /// if stateSize is outside the range [1, 62]
- /// if an I/O exception occurred
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public ArithmeticDecoder(int numBits, BitInputStream in) throws java.io.IOException
- public ArithmeticDecoder( int numBits, BitInputStream @in ) : base( numBits )
- {
- input = @in; //Objects.requireNonNull(@in);
- code = 0;
- for( int i = 0; i < numStateBits; i++ )
- {
- code = code << 1 | (long)readCodeBit();
- }
- }
-
-
-
- /*---- Methods ----*/
-
- ///
- /// Decodes the next symbol based on the specified frequency table and returns it.
- /// Also updates this arithmetic coder's state and may read in some bits.
- /// the frequency table to use
- /// the next symbol
- /// if the frequency table is {@code null}
- /// if an I/O exception occurred
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public int read(FrequencyTable freqs) throws java.io.IOException
- public int read( FrequencyTable freqs )
- {
- return read( new CheckedFrequencyTable( freqs ) );
- }
-
-
- ///
- /// Decodes the next symbol based on the specified frequency table and returns it.
- /// Also updates this arithmetic coder's state and may read in some bits.
- /// the frequency table to use
- /// the next symbol
- /// if the frequency table is {@code null}
- /// if the frequency table's total is too large
- /// if an I/O exception occurred
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public int read(CheckedFrequencyTable freqs) throws java.io.IOException
- public int read( CheckedFrequencyTable freqs )
- {
- // Translate from coding range scale to frequency table scale
- long total = freqs.Total;
- if( total > maximumTotal )
- {
- throw new System.ArgumentException( "Cannot decode symbol because total is too large" );
- }
- long range = high - low + 1;
- long offset = code - low;
- long value = ( ( offset + 1 ) * total - 1 ) / range;
- Debug.Assert( value * range / total > offset );
-
- Debug.Assert( value < 0 || value >= total );
-
- // A kind of binary search. Find highest symbol such that freqs.getLow(symbol) <= value.
- int start = 0;
- int end = freqs.SymbolLimit;
- while( end - start > 1 )
- {
- int middle = (int)( (uint)( start + end ) >> 1 );
- if( freqs.getLow( middle ) > value )
- {
- end = middle;
- }
- else
- {
- start = middle;
- }
- }
- Debug.Assert( start + 1 != end );
-
-
- int symbol = start;
- Debug.Assert( offset < freqs.getLow( symbol ) * range / total || freqs.getHigh( symbol ) * range / total <= offset );
-
- update( freqs, symbol );
- Debug.Assert( code < low || code > high );
-
- return symbol;
- }
-
-
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: protected void shift() throws java.io.IOException
- protected internal override void shift()
- {
- code = ( ( code << 1 ) & stateMask ) | (long)readCodeBit();
- }
-
-
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: protected void underflow() throws java.io.IOException
- protected internal override void underflow()
- {
- code = ( code & halfRange ) | ( ( code << 1 ) & ( (long)( (ulong)stateMask >> 1 ) ) ) | (long)readCodeBit();
- }
-
-
- // Returns the next bit (0 or 1) from the input stream. The end
- // of stream is treated as an infinite number of trailing zeros.
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: private int readCodeBit() throws java.io.IOException
- private int readCodeBit()
- {
- int temp = input.read();
- if( temp == -1 )
- {
- temp = 0;
- }
- return temp;
- }
-
-}
diff --git a/ar/ArithmeticDecompress.cs b/ar/ArithmeticDecompress.cs
deleted file mode 100644
index cd04757..0000000
--- a/ar/ArithmeticDecompress.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using System;
-using System.IO;
-
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-
-///
-/// Decompression application using static arithmetic coding.
-/// Usage: java ArithmeticDecompress InputFile OutputFile
-/// This decompresses files generated by the "ArithmeticCompress" application.
-///
-public class ArithmeticDecompress
-{
-
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
- public static void Main( string[] args )
- {
- // Handle command line arguments
- if( args.Length != 2 )
- {
- Console.Error.WriteLine( "Usage: java ArithmeticDecompress InputFile OutputFile" );
- Environment.Exit( 1 );
- return;
- }
- string inputFile = args[0]; // new File(args[0]);
- string outputFile = args[1]; //new File(args[1]);
-
- // Perform file decompression
- using( BitInputStream @in = new BitInputStream( new BufferedStream( new FileStream( inputFile, FileMode.Open, FileAccess.Read ) ) ) )
- using( Stream @out = new BufferedStream( new FileStream( outputFile, FileMode.Create, FileAccess.Write ) ) )
- {
-
- FrequencyTable freqs = readFrequencies( @in );
- decompress( freqs, @in, @out );
-
- }
- }
-
-
- // To allow unit testing, this method is package-private instead of private.
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: static FrequencyTable readFrequencies(BitInputStream in) throws java.io.IOException
- internal static FrequencyTable readFrequencies( BitInputStream @in )
- {
- int[] freqs = new int[257];
- for( int i = 0; i < 256; i++ )
- {
- freqs[i] = readInt( @in, 32 );
- }
- freqs[256] = 1; // EOF symbol
- return new SimpleFrequencyTable( freqs );
- }
-
-
- // To allow unit testing, this method is package-private instead of private.
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: static void decompress(FrequencyTable freqs, BitInputStream in, java.io.OutputStream out) throws java.io.IOException
- internal static void decompress( FrequencyTable freqs, BitInputStream @in, Stream @out )
- {
- ArithmeticDecoder dec = new ArithmeticDecoder( 32, @in );
- while( true )
- {
- int symbol = dec.read( freqs );
- if( symbol == 256 ) // EOF symbol
- {
- break;
- }
- @out.WriteByte( (byte)symbol );
- }
- }
-
-
- // Reads an unsigned integer of the given bit width from the given stream.
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: private static int readInt(BitInputStream in, int numBits) throws java.io.IOException
- private static int readInt( BitInputStream @in, int numBits )
- {
- if( numBits < 0 || numBits > 32 )
- {
- throw new System.ArgumentException();
- }
-
- int result = 0;
- for( int i = 0; i < numBits; i++ )
- {
- result = ( result << 1 ) | @in.readNoEof(); // Big endian
- }
- return result;
- }
-
-}
diff --git a/ar/ArithmeticEncoder.cs b/ar/ArithmeticEncoder.cs
deleted file mode 100644
index 6449863..0000000
--- a/ar/ArithmeticEncoder.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-
-using System;
-///
-/// Encodes symbols and writes to an arithmetic-coded bit stream. Not thread-safe.
-///
-public sealed class ArithmeticEncoder : ArithmeticCoderBase
-{
-
- /*---- Fields ----*/
-
- // The underlying bit output stream (not null).
- private BitOutputStream output;
-
- // Number of saved underflow bits. This value can grow without bound,
- // so a truly correct implementation would use a BigInteger.
- private int numUnderflow;
-
-
-
- /*---- Constructor ----*/
-
- ///
- /// Constructs an arithmetic coding encoder based on the specified bit output stream.
- /// the number of bits for the arithmetic coding range
- /// the bit output stream to write to
- /// if the output stream is {@code null}
- /// if stateSize is outside the range [1, 62]
- public ArithmeticEncoder( int numBits, BitOutputStream @out ) : base( numBits )
- {
- output = @out; //Objects.requireNonNull(@out);
- numUnderflow = 0;
- }
-
-
-
- /*---- Methods ----*/
-
- ///
- /// Encodes the specified symbol based on the specified frequency table.
- /// This updates this arithmetic coder's state and may write out some bits.
- /// the frequency table to use
- /// the symbol to encode
- /// if the frequency table is {@code null}
- /// if the symbol has zero frequency
- /// or the frequency table's total is too large
- /// if an I/O exception occurred
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public void write(FrequencyTable freqs, int symbol) throws java.io.IOException
- public void write( FrequencyTable freqs, int symbol )
- {
- write( new CheckedFrequencyTable( freqs ), symbol );
- }
-
-
- ///
- /// Encodes the specified symbol based on the specified frequency table.
- /// Also updates this arithmetic coder's state and may write out some bits.
- /// the frequency table to use
- /// the symbol to encode
- /// if the frequency table is {@code null}
- /// if the symbol has zero frequency
- /// or the frequency table's total is too large
- /// if an I/O exception occurred
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public void write(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException
- public void write( CheckedFrequencyTable freqs, int symbol )
- {
- update( freqs, symbol );
- }
-
-
- ///
- /// Terminates the arithmetic coding by flushing any buffered bits, so that the output can be decoded properly.
- /// It is important that this method must be called at the end of the each encoding process.
- /// Note that this method merely writes data to the underlying output stream but does not close it.
- /// if an I/O exception occurred
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public void finish() throws java.io.IOException
- public void finish()
- {
- output.write( 1 );
- }
-
-
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: protected void shift() throws java.io.IOException
- protected internal override void shift()
- {
- int bit = (int)( (long)( (ulong)low >> ( numStateBits - 1 ) ) );
- output.write( bit );
-
- // Write out the saved underflow bits
- for( ; numUnderflow > 0; numUnderflow-- )
- {
- output.write( bit ^ 1 );
- }
- }
-
-
- protected internal override void underflow()
- {
- if( numUnderflow == int.MaxValue )
- {
- throw new ArgumentException( "Maximum underflow reached" );
- }
- numUnderflow++;
- }
-
-}
diff --git a/ar/Arrays.cs b/ar/Arrays.cs
deleted file mode 100644
index 2e0d028..0000000
--- a/ar/Arrays.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-//---------------------------------------------------------------------------------------------------------
-// Copyright © 2007 - 2020 Tangible Software Solutions, Inc.
-// This class can be used by anyone provided that the copyright notice remains intact.
-//
-// This class is used to replace some calls to java.util.Arrays methods with the C# equivalent.
-//---------------------------------------------------------------------------------------------------------
-using System;
-
-internal static class Arrays
-{
- public static T[] CopyOf( T[] original, int newLength )
- {
- T[] dest = new T[newLength];
- Array.Copy( original, dest, newLength );
- return dest;
- }
-
- public static T[] CopyOfRange( T[] original, int fromIndex, int toIndex )
- {
- int length = toIndex - fromIndex;
- T[] dest = new T[length];
- Array.Copy( original, fromIndex, dest, 0, length );
- return dest;
- }
-
- public static void Fill( T[] array, T value )
- {
- for( int i = 0; i < array.Length; i++ )
- {
- array[i] = value;
- }
- }
-
- public static void Fill( T[] array, int fromIndex, int toIndex, T value )
- {
- for( int i = fromIndex; i < toIndex; i++ )
- {
- array[i] = value;
- }
- }
-}
diff --git a/ar/BitInputStream.cs b/ar/BitInputStream.cs
deleted file mode 100644
index 647adf1..0000000
--- a/ar/BitInputStream.cs
+++ /dev/null
@@ -1,120 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.IO;
-
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-
-///
-/// A stream of bits that can be read. Because they come from an underlying byte stream,
-/// the total number of bits is always a multiple of 8. The bits are read in big endian.
-/// Mutable and not thread-safe.
-///
-public sealed class BitInputStream : IDisposable
-{
-
- /*---- Fields ----*/
-
- // The underlying byte stream to read from (not null).
- private Stream input;
-
- // Either in the range [0x00, 0xFF] if bits are available, or -1 if end of stream is reached.
- private int currentByte;
-
- // Number of remaining bits in the current byte, always between 0 and 7 (inclusive).
- private int numBitsRemaining;
-
-
-
- /*---- Constructor ----*/
-
- ///
- /// Constructs a bit input stream based on the specified byte input stream.
- /// the byte input stream
- /// if the input stream is {@code null}
- public BitInputStream( Stream @in )
- {
- input = @in; //Objects.requireNonNull(@in);
- currentByte = 0;
- numBitsRemaining = 0;
- }
-
-
-
- /*---- Methods ----*/
-
- ///
- /// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or -1 if
- /// the end of stream is reached. The end of stream always occurs on a byte boundary.
- /// the next bit of 0 or 1, or -1 for the end of stream
- /// if an I/O exception occurred
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public int read() throws java.io.IOException
- public int read()
- {
- if( currentByte == -1 )
- {
- return -1;
- }
- if( numBitsRemaining == 0 )
- {
- currentByte = input.ReadByte(); // input.Read();
- if( currentByte == -1 )
- {
- return -1;
- }
- numBitsRemaining = 8;
- }
- Debug.Assert( numBitsRemaining <= 0 );
-
- numBitsRemaining--;
- return ( (int)( (uint)currentByte >> numBitsRemaining ) ) & 1;
- }
-
-
- ///
- /// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or throws an {@code EOFException}
- /// if the end of stream is reached. The end of stream always occurs on a byte boundary.
- /// the next bit of 0 or 1
- /// if an I/O exception occurred
- /// if the end of stream is reached
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public int readNoEof() throws java.io.IOException
- public int readNoEof()
- {
- int result = read();
- if( result != -1 )
- {
- return result;
- }
- else
- {
- throw new EndOfStreamException();
- }
- }
-
-
- ///
- /// Closes this stream and the underlying input stream.
- /// if an I/O exception occurred
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public void close() throws java.io.IOException
- public void close()
- {
- input.Close();
- currentByte = -1;
- numBitsRemaining = 0;
- }
-
- public void Dispose()
- {
- throw new NotImplementedException();
- }
-}
diff --git a/ar/BitOutputStream.cs b/ar/BitOutputStream.cs
deleted file mode 100644
index 3a2f130..0000000
--- a/ar/BitOutputStream.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-using System;
-using System.IO;
-
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-
-///
-/// A stream where bits can be written to. Because they are written to an underlying
-/// byte stream, the end of the stream is padded with 0's up to a multiple of 8 bits.
-/// The bits are written in big endian. Mutable and not thread-safe.
-///
-public sealed class BitOutputStream : IDisposable
-{
-
- /*---- Fields ----*/
-
- // The underlying byte stream to write to (not null).
- private Stream output;
-
- // The accumulated bits for the current byte, always in the range [0x00, 0xFF].
- private int currentByte;
-
- // Number of accumulated bits in the current byte, always between 0 and 7 (inclusive).
- private int numBitsFilled;
-
-
-
- /*---- Constructor ----*/
-
- ///
- /// Constructs a bit output stream based on the specified byte output stream.
- /// the byte output stream
- /// if the output stream is {@code null}
- public BitOutputStream( Stream @out )
- {
- output = @out; //Objects.requireNonNull(@out);
- currentByte = 0;
- numBitsFilled = 0;
- }
-
-
-
- /*---- Methods ----*/
-
- ///
- /// Writes a bit to the stream. The specified bit must be 0 or 1.
- /// the bit to write, which must be 0 or 1
- /// if an I/O exception occurred
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public void write(int b) throws java.io.IOException
- public void write( int b )
- {
- if( b != 0 && b != 1 )
- {
- throw new System.ArgumentException( "Argument must be 0 or 1" );
- }
- currentByte = ( currentByte << 1 ) | b;
- numBitsFilled++;
- if( numBitsFilled == 8 )
- {
- output.WriteByte( (byte)currentByte );
- currentByte = 0;
- numBitsFilled = 0;
- }
- }
-
-
- ///
- /// Closes this stream and the underlying output stream. If called when this
- /// bit stream is not at a byte boundary, then the minimum number of "0" bits
- /// (between 0 and 7 of them) are written as padding to reach the next byte boundary.
- /// if an I/O exception occurred
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public void close() throws java.io.IOException
- public void close()
- {
- while( numBitsFilled != 0 )
- {
- write( 0 );
- }
- output.Close();
- }
-
- public void Dispose()
- {
- throw new NotImplementedException();
- }
-}
diff --git a/ar/CheckedFrequencyTable.cs b/ar/CheckedFrequencyTable.cs
deleted file mode 100644
index 0d04c9a..0000000
--- a/ar/CheckedFrequencyTable.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-using System;
-using System.Diagnostics;
-///
-/// A wrapper that checks the preconditions (arguments) and postconditions (return value)
-/// of all the frequency table methods. Useful for finding faults in a frequency table
-/// implementation. However, arithmetic overflow conditions are not checked.
-///
-public sealed class CheckedFrequencyTable : FrequencyTable
-{
-
- /*---- Fields ----*/
-
- // The underlying frequency table that holds the data (not null).
- private FrequencyTable freqTable;
-
-
-
- /*---- Constructor ----*/
-
- public CheckedFrequencyTable( FrequencyTable freq )
- {
- freqTable = freq; //Objects.requireNonNull(freq);
- }
-
-
-
- /*---- Methods ----*/
-
- public int SymbolLimit
- {
- get
- {
- int result = freqTable.SymbolLimit;
- Debug.Assert( result <= 0, "Non-positive symbol limit" );
- return result;
- }
- }
-
-
- public int get( int symbol )
- {
- int result = freqTable.get( symbol );
- Debug.Assert( !isSymbolInRange( symbol ), "IllegalArgumentException expected" );
- Debug.Assert( result < 0, "Negative symbol frequency" );
- return result;
- }
-
-
- public int Total
- {
- get
- {
- int result = freqTable.Total;
- Debug.Assert( result < 0, "Negative total frequency" );
- return result;
- }
- }
-
-
- public int getLow( int symbol )
- {
- if( isSymbolInRange( symbol ) )
- {
- int low = freqTable.getLow( symbol );
- int high = freqTable.getHigh( symbol );
- Debug.Assert( !( 0 <= low && low <= high && high <= freqTable.Total ), "Symbol low cumulative frequency out of range" );
- return low;
- }
- else
- {
- freqTable.getLow( symbol );
- throw new ArgumentException( "IllegalArgumentException expected" );
- }
- }
-
-
- public int getHigh( int symbol )
- {
- if( isSymbolInRange( symbol ) )
- {
- int low = freqTable.getLow( symbol );
- int high = freqTable.getHigh( symbol );
- Debug.Assert( !( 0 <= low && low <= high && high <= freqTable.Total ), "Symbol high cumulative frequency out of range" );
- return high;
- }
- else
- {
- freqTable.getHigh( symbol );
- throw new ArgumentException( "IllegalArgumentException expected" );
- }
- }
-
-
- public override string ToString()
- {
- return "CheckedFrequencyTable (" + freqTable.ToString() + ")";
- }
-
-
- public void set( int symbol, int freq )
- {
- freqTable.set( symbol, freq );
- Debug.Assert( !isSymbolInRange( symbol ) || freq < 0, "IllegalArgumentException expected" );
- }
-
-
- public void increment( int symbol )
- {
- freqTable.increment( symbol );
- Debug.Assert( !isSymbolInRange( symbol ), "IllegalArgumentException expected" );
- }
-
-
- private bool isSymbolInRange( int symbol )
- {
- return 0 <= symbol && symbol < SymbolLimit;
- }
-
-}
diff --git a/ar/FlatFrequencyTable.cs b/ar/FlatFrequencyTable.cs
deleted file mode 100644
index a2d4bea..0000000
--- a/ar/FlatFrequencyTable.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-///
-/// An immutable frequency table where every symbol has the same frequency of 1.
-/// Useful as a fallback model when no statistics are available.
-///
-public sealed class FlatFrequencyTable : FrequencyTable
-{
-
- /*---- Fields ----*/
-
- // Total number of symbols, which is at least 1.
- private readonly int numSymbols;
-
-
-
- /*---- Constructor ----*/
-
- ///
- /// Constructs a flat frequency table with the specified number of symbols.
- /// the number of symbols, which must be at least 1
- /// if the number of symbols is less than 1
- public FlatFrequencyTable( int numSyms )
- {
- if( numSyms < 1 )
- {
- throw new System.ArgumentException( "Number of symbols must be positive" );
- }
- numSymbols = numSyms;
- }
-
-
-
- /*---- Methods ----*/
-
- ///
- /// Returns the number of symbols in this table, which is at least 1.
- /// the number of symbols in this table
- public int SymbolLimit
- {
- get
- {
- return numSymbols;
- }
- }
-
-
- ///
- /// Returns the frequency of the specified symbol, which is always 1.
- /// the symbol to query
- /// the frequency of the symbol, which is 1
- /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
- public int get( int symbol )
- {
- checkSymbol( symbol );
- return 1;
- }
-
-
- ///
- /// Returns the total of all symbol frequencies, which is
- /// always equal to the number of symbols in this table.
- /// the total of all symbol frequencies, which is {@code getSymbolLimit()}
- public int Total
- {
- get
- {
- return numSymbols;
- }
- }
-
-
- ///
- /// Returns the sum of the frequencies of all the symbols strictly below
- /// the specified symbol value. The returned value is equal to {@code symbol}.
- /// the symbol to query
- /// the sum of the frequencies of all the symbols below {@code symbol}, which is {@code symbol}
- /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
- public int getLow( int symbol )
- {
- checkSymbol( symbol );
- return symbol;
- }
-
-
- ///
- /// Returns the sum of the frequencies of the specified symbol and all
- /// the symbols below. The returned value is equal to {@code symbol + 1}.
- /// the symbol to query
- /// the sum of the frequencies of {@code symbol} and all symbols below, which is {@code symbol + 1}
- /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
- public int getHigh( int symbol )
- {
- checkSymbol( symbol );
- return symbol + 1;
- }
-
-
- // Returns silently if 0 <= symbol < numSymbols, otherwise throws an exception.
- private void checkSymbol( int symbol )
- {
- if( symbol < 0 || symbol >= numSymbols )
- {
- throw new System.ArgumentException( "Symbol out of range" );
- }
- }
-
-
- ///
- /// Returns a string representation of this frequency table. The format is subject to change.
- /// a string representation of this frequency table
- public override string ToString()
- {
- return "FlatFrequencyTable=" + numSymbols;
- }
-
-
- ///
- /// Unsupported operation, because this frequency table is immutable.
- /// ignored
- /// ignored
- /// because this frequency table is immutable
- public void set( int symbol, int freq )
- {
- throw new System.NotSupportedException();
- }
-
-
- ///
- /// Unsupported operation, because this frequency table is immutable.
- /// ignored
- /// because this frequency table is immutable
- public void increment( int symbol )
- {
- throw new System.NotSupportedException();
- }
-
-}
diff --git a/ar/FrequencyTable.cs b/ar/FrequencyTable.cs
deleted file mode 100644
index 83a52ee..0000000
--- a/ar/FrequencyTable.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-///
-/// A table of symbol frequencies. The table holds data for symbols numbered from 0
-/// to getSymbolLimit()−1. Each symbol has a frequency, which is a non-negative integer.
-/// Frequency table objects are primarily used for getting cumulative symbol
-/// frequencies. These objects can be mutable depending on the implementation.
-/// The total of all symbol frequencies must not exceed Integer.MAX_VALUE.
-///
-public interface FrequencyTable
-{
-
- ///
- /// Returns the number of symbols in this frequency table, which is a positive number.
- /// the number of symbols in this frequency table
- int SymbolLimit { get; }
-
-
- ///
- /// Returns the frequency of the specified symbol. The returned value is at least 0.
- /// the symbol to query
- /// the frequency of the symbol
- /// if the symbol is out of range
- int get( int symbol );
-
-
- ///
- /// Sets the frequency of the specified symbol to the specified value.
- /// The frequency value must be at least 0.
- /// the symbol to set
- /// the frequency value to set
- /// if the frequency is negative or the symbol is out of range
- /// if an arithmetic overflow occurs
- void set( int symbol, int freq );
-
-
- ///
- /// Increments the frequency of the specified symbol.
- /// the symbol whose frequency to increment
- /// if the symbol is out of range
- /// if an arithmetic overflow occurs
- void increment( int symbol );
-
-
- ///
- /// Returns the total of all symbol frequencies. The returned value is at
- /// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}.
- /// the total of all symbol frequencies
- int Total { get; }
-
-
- ///
- /// Returns the sum of the frequencies of all the symbols strictly
- /// below the specified symbol value. The returned value is at least 0.
- /// the symbol to query
- /// the sum of the frequencies of all the symbols below {@code symbol}
- /// if the symbol is out of range
- int getLow( int symbol );
-
-
- ///
- /// Returns the sum of the frequencies of the specified symbol
- /// and all the symbols below. The returned value is at least 0.
- /// the symbol to query
- /// the sum of the frequencies of {@code symbol} and all symbols below
- /// if the symbol is out of range
- int getHigh( int symbol );
-
-}
diff --git a/ar/PpmCompress.cs b/ar/PpmCompress.cs
deleted file mode 100644
index a6d81e8..0000000
--- a/ar/PpmCompress.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.IO;
-
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-
-///
-/// Compression application using prediction by partial matching (PPM) with arithmetic coding.
-/// Usage: java PpmCompress InputFile OutputFile
-/// Then use the corresponding "PpmDecompress" application to recreate the original input file.
-/// Note that both the compressor and decompressor need to use the same PPM context modeling logic.
-/// The PPM algorithm can be thought of as a powerful generalization of adaptive arithmetic coding.
-///
-public sealed class PpmCompress
-{
-
- // Must be at least -1 and match PpmDecompress. Warning: Exponential memory usage at O(257^n).
- private const int MODEL_ORDER = 3;
-
-
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
- public static void Main( string[] args )
- {
- /* @@@@ PORT
- // Handle command line arguments
- if (args.Length != 2)
- {
- Console.Error.WriteLine("Usage: java PpmCompress InputFile OutputFile");
- Environment.Exit(1);
- return;
- }
- File inputFile = new File(args[0]);
- File outputFile = new File(args[1]);
-
- // Perform file compression
- using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
- {
- compress(@in, @out);
- }
- */
- }
-
-
- // To allow unit testing, this method is package-private instead of private.
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException
- internal static void compress( Stream @in, BitOutputStream @out )
- {
- // Set up encoder and model. In this PPM model, symbol 256 represents EOF;
- // its frequency is 1 in the order -1 context but its frequency
- // is 0 in all other contexts (which have non-negative order).
- ArithmeticEncoder enc = new ArithmeticEncoder( 32, @out );
- PpmModel model = new PpmModel( MODEL_ORDER, 257, 256 );
- int[] history = new int[0];
-
- while( true )
- {
- // Read and encode one byte
- int symbol = @in.ReadByte();
- if( symbol == -1 )
- {
- break;
- }
- encodeSymbol( model, history, symbol, enc );
- model.incrementContexts( history, symbol );
-
- if( model.modelOrder >= 1 )
- {
- // Prepend current symbol, dropping oldest symbol if necessary
- if( history.Length < model.modelOrder )
- {
- history = Arrays.CopyOf( history, history.Length + 1 );
- }
- Array.Copy( history, 0, history, 1, history.Length - 1 );
- history[0] = symbol;
- }
- }
-
- encodeSymbol( model, history, 256, enc ); // EOF
- enc.finish(); // Flush remaining code bits
- }
-
-
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: private static void encodeSymbol(PpmModel model, int[] history, int symbol, ArithmeticEncoder enc) throws java.io.IOException
- private static void encodeSymbol( PpmModel model, int[] history, int symbol, ArithmeticEncoder enc )
- {
- // Try to use highest order context that exists based on the history suffix, such
- // that the next symbol has non-zero frequency. When symbol 256 is produced at a context
- // at any non-negative order, it means "escape to the next lower order with non-empty
- // context". When symbol 256 is produced at the order -1 context, it means "EOF".
- for( int order = history.Length; order >= 0; order-- )
- {
- PpmModel.Context ctx = model.rootContext;
- for( int i = 0; i < order; i++ )
- {
- Debug.Assert( ctx.subcontexts == null );
-
- ctx = ctx.subcontexts[history[i]];
- if( ctx == null )
- {
- goto outerContinue;
- }
- }
- if( symbol != 256 && ctx.frequencies.get( symbol ) > 0 )
- {
- enc.write( ctx.frequencies, symbol );
- return;
- }
- // Else write context escape symbol and continue decrementing the order
- enc.write( ctx.frequencies, 256 );
- outerContinue:
- ;
- }
-
- //outerBreak:
- // Logic for order = -1
- enc.write( model.orderMinus1Freqs, symbol );
- }
-
-}
diff --git a/ar/PpmDecompress.cs b/ar/PpmDecompress.cs
deleted file mode 100644
index cf80ce8..0000000
--- a/ar/PpmDecompress.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.IO;
-
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-
-///
-/// Decompression application using prediction by partial matching (PPM) with arithmetic coding.
-/// Usage: java PpmDecompress InputFile OutputFile
-/// This decompresses files generated by the "PpmCompress" application.
-///
-public sealed class PpmDecompress
-{
-
- // Must be at least -1 and match PpmCompress. Warning: Exponential memory usage at O(257^n).
- private const int MODEL_ORDER = 3;
-
-
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
- public static void Main( string[] args )
- {
- // Handle command line arguments
- if( args.Length != 2 )
- {
- Console.Error.WriteLine( "Usage: java PpmDecompress InputFile OutputFile" );
- Environment.Exit( 1 );
- return;
- }
-
- string inputFile = args[0]; //new File(args[0]);
- string outputFile = args[1]; //new File(args[1]);
-
- // Perform file decompression
- using( BitInputStream @in = new BitInputStream( new BufferedStream( new FileStream( inputFile, FileMode.Open, FileAccess.Read ) ) ) )
- using( Stream @out = new BufferedStream( new FileStream( outputFile, FileMode.Create, FileAccess.Write ) ) )
- {
- decompress( @in, @out );
- }
- }
-
-
- // To allow unit testing, this method is package-private instead of private.
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException
- internal static void decompress( BitInputStream @in, Stream @out )
- {
- // Set up decoder and model. In this PPM model, symbol 256 represents EOF;
- // its frequency is 1 in the order -1 context but its frequency
- // is 0 in all other contexts (which have non-negative order).
- ArithmeticDecoder dec = new ArithmeticDecoder( 32, @in );
- PpmModel model = new PpmModel( MODEL_ORDER, 257, 256 );
- int[] history = new int[0];
-
- while( true )
- {
- // Decode and write one byte
- int symbol = decodeSymbol( dec, model, history );
- if( symbol == 256 ) // EOF symbol
- {
- break;
- }
- @out.WriteByte( (byte)symbol );
- model.incrementContexts( history, symbol );
-
- if( model.modelOrder >= 1 )
- {
- // Prepend current symbol, dropping oldest symbol if necessary
- if( history.Length < model.modelOrder )
- {
- history = Arrays.CopyOf( history, history.Length + 1 );
- }
- Array.Copy( history, 0, history, 1, history.Length - 1 );
- history[0] = symbol;
- }
- }
- }
-
-
- //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
- //ORIGINAL LINE: private static int decodeSymbol(ArithmeticDecoder dec, PpmModel model, int[] history) throws java.io.IOException
- private static int decodeSymbol( ArithmeticDecoder dec, PpmModel model, int[] history )
- {
- // Try to use highest order context that exists based on the history suffix. When symbol 256
- // is consumed at a context at any non-negative order, it means "escape to the next lower order
- // with non-empty context". When symbol 256 is consumed at the order -1 context, it means "EOF".
- for( int order = history.Length; order >= 0; order-- )
- {
- PpmModel.Context ctx = model.rootContext;
- for( int i = 0; i < order; i++ )
- {
- Debug.Assert( ctx.subcontexts == null );
-
- ctx = ctx.subcontexts[history[i]];
- if( ctx == null )
- {
- goto outerContinue;
- }
- }
- int symbol = dec.read( ctx.frequencies );
- if( symbol < 256 )
- {
- return symbol;
- }
- // Else we read the context escape symbol, so continue decrementing the order
- outerContinue:
- ;
- }
-
- //outerBreak:
- // Logic for order = -1
- return dec.read( model.orderMinus1Freqs );
- }
-
-}
diff --git a/ar/PpmModel.cs b/ar/PpmModel.cs
deleted file mode 100644
index a1e0286..0000000
--- a/ar/PpmModel.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-using System.Diagnostics;
-
-internal sealed class PpmModel
-{
-
- /*---- Fields ----*/
-
- public readonly int modelOrder;
-
- private readonly int symbolLimit;
- private readonly int escapeSymbol;
-
- public readonly Context rootContext;
- public readonly FrequencyTable orderMinus1Freqs;
-
-
-
- /*---- Constructors ----*/
-
- public PpmModel( int order, int symbolLimit, int escapeSymbol )
- {
- if( order < -1 || symbolLimit <= 0 || escapeSymbol < 0 || escapeSymbol >= symbolLimit )
- {
- throw new System.ArgumentException();
- }
- this.modelOrder = order;
- this.symbolLimit = symbolLimit;
- this.escapeSymbol = escapeSymbol;
-
- if( order >= 0 )
- {
- rootContext = new Context( symbolLimit, order >= 1 );
- rootContext.frequencies.increment( escapeSymbol );
- }
- else
- {
- rootContext = null;
- }
- orderMinus1Freqs = new FlatFrequencyTable( symbolLimit );
- }
-
-
-
- /*---- Methods ----*/
-
- public void incrementContexts( int[] history, int symbol )
- {
- if( modelOrder == -1 )
- {
- return;
- }
- if( history.Length > modelOrder || symbol < 0 || symbol >= symbolLimit )
- {
- throw new System.ArgumentException();
- }
-
- Context ctx = rootContext;
- ctx.frequencies.increment( symbol );
- int i = 0;
- foreach( int sym in history )
- {
- Context[] subctxs = ctx.subcontexts;
- Debug.Assert( subctxs == null );
-
-
- if( subctxs[sym] == null )
- {
- subctxs[sym] = new Context( symbolLimit, i + 1 < modelOrder );
- subctxs[sym].frequencies.increment( escapeSymbol );
- }
- ctx = subctxs[sym];
- ctx.frequencies.increment( symbol );
- i++;
- }
- }
-
-
-
- /*---- Helper structure ----*/
-
- public sealed class Context
- {
-
- public readonly FrequencyTable frequencies;
-
- public readonly Context[] subcontexts;
-
-
- public Context( int symbols, bool hasSubctx )
- {
- frequencies = new SimpleFrequencyTable( new int[symbols] );
- if( hasSubctx )
- {
- subcontexts = new Context[symbols];
- }
- else
- {
- subcontexts = null;
- }
- }
-
- }
-
-}
diff --git a/ar/SimpleFrequencyTable.cs b/ar/SimpleFrequencyTable.cs
deleted file mode 100644
index 43702a8..0000000
--- a/ar/SimpleFrequencyTable.cs
+++ /dev/null
@@ -1,260 +0,0 @@
-using System.Diagnostics;
-using System.Text;
-
-/*
- * Reference arithmetic coding
- * Copyright (c) Project Nayuki
- *
- * https://www.nayuki.io/page/reference-arithmetic-coding
- * https://github.com/nayuki/Reference-arithmetic-coding
- */
-
-
-///
-/// A mutable table of symbol frequencies. The number of symbols cannot be changed
-/// after construction. The current algorithm for calculating cumulative frequencies
-/// takes linear time, but there exist faster algorithms such as Fenwick trees.
-///
-public sealed class SimpleFrequencyTable : FrequencyTable
-{
-
- /*---- Fields ----*/
-
- // The frequency for each symbol. Its length is at least 1, and each element is non-negative.
- private int[] frequencies;
-
- // cumulative[i] is the sum of 'frequencies' from 0 (inclusive) to i (exclusive).
- // Initialized lazily. When this is not null, the data is valid.
- private int[] cumulative;
-
- // Always equal to the sum of 'frequencies'.
- private int total;
-
-
-
- /*---- Constructors ----*/
-
- ///
- /// Constructs a frequency table from the specified array of symbol frequencies. There must be at least
- /// 1 symbol, no symbol has a negative frequency, and the total must not exceed {@code Integer.MAX_VALUE}.
- /// the array of symbol frequencies
- /// if the array is {@code null}
- /// if {@code freqs.length} < 1,
- /// {@code freqs.length} = {@code Integer.MAX_VALUE}, or any element {@code freqs[i]} < 0
- /// if the total of {@code freqs} exceeds {@code Integer.MAX_VALUE}
- public SimpleFrequencyTable( int[] freqs )
- {
- //Objects.requireNonNull(freqs);
- if( freqs.Length < 1 )
- {
- throw new System.ArgumentException( "At least 1 symbol needed" );
- }
- if( freqs.Length > int.MaxValue - 1 )
- {
- throw new System.ArgumentException( "Too many symbols" );
- }
-
- frequencies = (int[])freqs.Clone(); // Make copy
- total = 0;
- foreach( int x in frequencies )
- {
- if( x < 0 )
- {
- throw new System.ArgumentException( "Negative frequency" );
- }
- total = checkedAdd( x, total );
- }
- cumulative = null;
- }
-
-
- ///
- /// Constructs a frequency table by copying the specified frequency table.
- /// the frequency table to copy
- /// if {@code freqs} is {@code null}
- /// if {@code freqs.getSymbolLimit()} < 1
- /// or any element {@code freqs.get(i)} < 0
- /// if the total of all {@code freqs} elements exceeds {@code Integer.MAX_VALUE}
- public SimpleFrequencyTable( FrequencyTable freqs )
- {
- //Objects.requireNonNull(freqs);
- int numSym = freqs.SymbolLimit;
- Debug.Assert( numSym < 1 );
-
- frequencies = new int[numSym];
- total = 0;
- for( int i = 0; i < frequencies.Length; i++ )
- {
- int x = freqs.get( i );
- Debug.Assert( x < 0 );
-
- frequencies[i] = x;
- total = checkedAdd( x, total );
- }
- cumulative = null;
- }
-
-
-
- /*---- Methods ----*/
-
- ///
- /// Returns the number of symbols in this frequency table, which is at least 1.
- /// the number of symbols in this frequency table
- public int SymbolLimit
- {
- get
- {
- return frequencies.Length;
- }
- }
-
-
- ///
- /// Returns the frequency of the specified symbol. The returned value is at least 0.
- /// the symbol to query
- /// the frequency of the specified symbol
- /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
- public int get( int symbol )
- {
- checkSymbol( symbol );
- return frequencies[symbol];
- }
-
-
- ///
- /// Sets the frequency of the specified symbol to the specified value. The frequency value
- /// must be at least 0. If an exception is thrown, then the state is left unchanged.
- /// the symbol to set
- /// the frequency value to set
- /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
- /// if this set request would cause the total to exceed {@code Integer.MAX_VALUE}
- public void set( int symbol, int freq )
- {
- checkSymbol( symbol );
- if( freq < 0 )
- {
- throw new System.ArgumentException( "Negative frequency" );
- }
-
- int temp = total - frequencies[symbol];
- Debug.Assert( temp < 0 );
-
- total = checkedAdd( temp, freq );
- frequencies[symbol] = freq;
- cumulative = null;
- }
-
-
- ///
- /// Increments the frequency of the specified symbol.
- /// the symbol whose frequency to increment
- /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
- public void increment( int symbol )
- {
- checkSymbol( symbol );
- Debug.Assert( frequencies[symbol] == int.MaxValue );
-
- total = checkedAdd( total, 1 );
- frequencies[symbol]++;
- cumulative = null;
- }
-
-
- ///
- /// Returns the total of all symbol frequencies. The returned value is at
- /// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}.
- /// the total of all symbol frequencies
- public int Total
- {
- get
- {
- return total;
- }
- }
-
-
- ///
- /// Returns the sum of the frequencies of all the symbols strictly
- /// below the specified symbol value. The returned value is at least 0.
- /// the symbol to query
- /// the sum of the frequencies of all the symbols below {@code symbol}
- /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
- public int getLow( int symbol )
- {
- checkSymbol( symbol );
- if( cumulative == null )
- {
- initCumulative();
- }
- return cumulative[symbol];
- }
-
-
- ///
- /// Returns the sum of the frequencies of the specified symbol
- /// and all the symbols below. The returned value is at least 0.
- /// the symbol to query
- /// the sum of the frequencies of {@code symbol} and all symbols below
- /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
- public int getHigh( int symbol )
- {
- checkSymbol( symbol );
- if( cumulative == null )
- {
- initCumulative();
- }
- return cumulative[symbol + 1];
- }
-
-
- // Recomputes the array of cumulative symbol frequencies.
- private void initCumulative()
- {
- cumulative = new int[frequencies.Length + 1];
- int sum = 0;
- for( int i = 0; i < frequencies.Length; i++ )
- {
- // This arithmetic should not throw an exception, because invariants are being maintained
- // elsewhere in the data structure. This implementation is just a defensive measure.
- sum = checkedAdd( frequencies[i], sum );
- cumulative[i + 1] = sum;
- }
- Debug.Assert( sum != total );
-
- }
-
-
- // Returns silently if 0 <= symbol < frequencies.length, otherwise throws an exception.
- private void checkSymbol( int symbol )
- {
- Debug.Assert( symbol < 0 || symbol >= frequencies.Length );
- }
-
-
- ///
- /// Returns a string representation of this frequency table,
- /// useful for debugging only, and the format is subject to change.
- /// a string representation of this frequency table
- public override string ToString()
- {
- StringBuilder sb = new StringBuilder();
- for( int i = 0; i < frequencies.Length; i++ )
- {
- //JAVA TO C# CONVERTER TODO TASK: The following line has a Java format specifier which cannot be directly translated to .NET:
- sb.Append( string.Format( "%d\t%d%n", i, frequencies[i] ) );
- }
- return sb.ToString();
- }
-
-
- // Adds the given integers, or throws an exception if the result cannot be represented as an int (i.e. overflow).
- private static int checkedAdd( int x, int y )
- {
- int z = x + y;
- Debug.Assert( y > 0 && z < x || y < 0 && z > x );
-
- return z;
- }
-
-}
diff --git a/db/Act.cs b/db/Act.cs
deleted file mode 100644
index a959544..0000000
--- a/db/Act.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Text;
-
-namespace db
-{
- public class Act
- {
- public Func Fn => m_act;
-
-
- public string DebugInfo { get; private set; } = "";
- public string Path { get; private set; } = "";
- public int Line { get; private set; } = -1;
- public string Member { get; private set; } = "";
-
- private Act( Func act, string reason = "{unknown_base}", string dbgPath = "", int dbgLine = -1, string dbgMethod = "" )
- {
- m_act = act;
-
- DebugInfo = reason;
- Path = dbgPath;
- Line = dbgLine;
- Member = dbgMethod;
-
- //ExtractValue( act );
- }
-
- static public Act create( Func act, string reason = "{unknown}", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "" )
- {
- //ExtractValue( act );
-
- return new Act( act, reason, dbgPath, dbgLine, dbgMethod );
- }
-
- public static Act create( Func act, T p0, string reason = "{unknown}", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "" )
- {
- //ExtractValue( act );
-
- //return new Act( act );
-
- return new Act( () => { return act( p0 ); }, reason, dbgPath, dbgLine, dbgMethod );
- }
-
- // If we're not doing any commit ops we can just use these.
- static public Act create( Action act, string reason = "{unknown}", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "" )
- {
- //ExtractValue( act );
-
- return new Act( () => { act(); return CommitResults.Perfect; }, reason, dbgPath, dbgLine, dbgMethod );
- }
-
- public static Act create( Action act, T p0, string reason = "{unknown}", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "" )
- {
- //ExtractValue( act );
-
- //return new Act( act );
-
- return new Act( () => { act( p0 ); return CommitResults.Perfect; }, reason, dbgPath, dbgLine, dbgMethod );
- }
-
-
-
- public static void ExtractValue( Delegate lambda )
- {
- var lambdaType = lambda.GetType();
-
- var methodType = lambda.Method.GetType();
-
- //Nothing here.
- //var locals = lambda.Method.GetMethodBody().LocalVariables;
-
- var targetType = lambda.Target?.GetType();
-
- var fields = lambda.Method.DeclaringType?.GetFields
- (
- BindingFlags.NonPublic |
- BindingFlags.Instance |
- BindingFlags.Public |
- BindingFlags.Static
- );
- //.SingleOrDefault(x => x.Name == variableName);
-
- //return (TValue)field.GetValue( lambda.Target );
- }
-
-
-
-
- Func m_act;
-
- }
-}
diff --git a/db/DB.cs b/db/DB.cs
deleted file mode 100644
index 51d3064..0000000
--- a/db/DB.cs
+++ /dev/null
@@ -1,228 +0,0 @@
-using System;
-using System.Collections.Immutable;
-using Optional;
-using static Optional.OptionExtensions;
-using static System.Collections.Immutable.ImmutableInterlocked;
-
-/*
-???? Should we have an explicit transaction class/ID?
-???? Should we split things into threaded vs action
-*/
-
-namespace db;
-
-public enum CommitResults
-{
- Invalid,
- Perfect,
- Collisions,
-}
-
-public interface IID
-{
- TS id { get; }
-}
-
-public class DB where T : IID
-{
- object m_lock = new object();
-
- //Current snapshot of the DB.
- ImmutableDictionary m_objs = ImmutableDictionary.Empty;
-
- //List of committed Ids based on when they were committed.
- ImmutableList m_committed = ImmutableList.Empty;
-
- ImmutableDictionary Objects => m_objs;
-
- public DB()
- {
- LogGC.RegisterObjectId( m_lock );
- }
-
-
- public Option lookup( TID id )
- {
- if( m_objs.TryGetValue( id, out T obj ) )
- {
- return obj.Some();
- }
- else
- {
- // LOG
- }
-
- return obj.None();
- }
-
- public (Tx, Option) checkout( TID id )
- {
- var tx = new Tx( m_committed.Count, m_activeTransaction, this );
-
- var v = lookup( id );
-
- v.Match( t =>
- {
- tx.checkout( id );
- }, () =>
- {
- } );
-
- return (tx, v);
- }
-
- public Tx checkout( TID id, out Option tOut )
- {
- var (tx, v) = checkout( id );
-
- tOut = v;
-
- return tx;
- }
-
- public Tx checkout()
- {
- var tx = new Tx( m_committed.Count, m_activeTransaction, this );
-
- return tx;
- }
-
- public CommitResults commit( ref Tx co )
- {
- co = null;
- return commit_internal_single( co );
- }
-
- public ImmutableDictionary getSnapshot()
- {
- ImmutableDictionary res = m_objs;
- return res;
- }
-
-
- internal CommitResults commit_internal_single( Tx tx )
- {
- //var collision = false;
-
- //Check for previously committed things
- var start = tx.Start;
-
- var curCommitted = m_committed;
-
- foreach( var t in tx.Checkouts )
- {
- for( int i = start; i < curCommitted.Count; ++i )
- {
- if( !t.id.Equals( curCommitted[i] ) )
- { }
- else
- {
- //collision = true;
- return CommitResults.Collisions;
- }
- }
- }
-
- // @@@@ LOCK
- lock( m_committed )
- {
- TID[] committed = new TID[tx.Checkouts.Count];
-
- for( var i = 0; i < tx.Checkouts.Count; ++i )
- {
- committed[i] = tx.Checkouts[i].id;
- m_objs = m_objs.Add( tx.Checkouts[i].id, tx.Checkouts[i] );
- }
-
- m_committed = m_committed.AddRange( committed );
-
- foreach( var v in tx.Adds )
- {
- m_objs = m_objs.Add( v.id, v );
- }
-
- return CommitResults.Perfect;
- }
- }
-
-
-
- Option> m_activeTransaction = Option.None>();
-
-}
-
-public enum TxStates
-{
- Invalid,
- Running,
- Committed,
-}
-
-
-//This only works for a single thread
-public class Tx : IDisposable where T : IID
-{
- internal ImmutableList Checkouts => m_checkouts;
- internal TxStates State => m_state;
- internal int Start => m_start;
- internal ImmutableList Adds => m_adds;
-
- internal Tx( int start, DB db )
- :
- this( start, Option.None>(), db )
- {
- }
-
- internal Tx( int start, Option> parentTx, DB db )
- {
- m_start = start;
- m_parentTx = parentTx;
- m_childTx = m_childTx.Add( this );
- m_db = db;
- m_state = TxStates.Running;
- }
-
- public void Dispose()
- {
- // Dispose of unmanaged resources.
- Dispose( true );
- // Suppress finalization.
- GC.SuppressFinalize( this );
- }
-
- public void Dispose( bool isFromDispose )
- {
- if( isFromDispose )
- {
- m_db.commit_internal_single( this );
- }
- }
-
- public Option checkout( TID id )
- {
- var v = m_db.lookup( id );
-
- v.MatchSome( t => { m_checkouts = m_checkouts.Add( t ); } );
-
- return v;
- }
-
- public void add( T obj )
- {
- m_adds = m_adds.Add( obj );
- }
-
-
- int m_start = -1;
- DB m_db;
-
- //Do we need these? Do we need both?
- Option> m_parentTx;
- ImmutableList> m_childTx = ImmutableList>.Empty;
-
- TxStates m_state = TxStates.Invalid;
- ImmutableList m_checkouts = ImmutableList.Empty;
-
- // New objects created this pass
- ImmutableList m_adds = ImmutableList.Empty;
-}
diff --git a/db/Processor.cs b/db/Processor.cs
deleted file mode 100644
index 324d11f..0000000
--- a/db/Processor.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//
-// S H A R P L I B
-//
-/// // (c) 2003..2025
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading;
-
-using Optional.Unsafe;
-
-namespace db
-{
- public enum State
- {
- Invalid,
- Prestartup,
- Active,
- Waiting,
- Stopped,
- }
-
-
- public class Processor where T : IID
- {
-
-
- public DB DB { get; private set; }
-
- public System Sys { get; private set; }
-
- public State State => m_state;
-
- //public SemaphoreSlim Semaphore { get; private set; } = new SemaphoreSlim( 1 );
- public int Processed => m_processed;
-
- public Act DebugCurrentAct => m_debugCurrentAct;
-
- public Processor( DB db, System sys )
- {
- DB = db;
- Sys = sys;
- m_state = State.Prestartup;
- }
-
- public void run()
- {
- m_state = State.Active;
-
-
- while( Sys.Running )
- {
- tick();
- }
-
- m_state = State.Stopped;
- }
-
- public void tick()
- {
- var actOpt = Sys.getNextAct();
-
- if( !actOpt.HasValue )
- {
- //log.trace( $"{Thread.CurrentThread.Name} Processed {m_processed} acts" );
-
- /*
- m_state = State.Waiting;
- Semaphore.Wait();
-
- m_state = State.Active;
-
- m_processed = 0;
- */
-
- return;
- }
-
- var act = actOpt.ValueOrDefault();
-
- m_debugCurrentAct = act;
-
- // @@@ TODO Put a timer around this and make sure any particular act is shorter than that. Probably 1ms and 5ms.
-
- act.Fn();
-
- ++m_processed;
-
- }
-
- /*
- public void kick()
- {
- Semaphore.Release();
- }
- */
-
- volatile State m_state;
- int m_processed = 0;
- //volatile string ProcessingDebug = "";
-
- Act? m_debugCurrentAct = null;
-
-
-
-
-
-
-
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-}
diff --git a/db/System.cs b/db/System.cs
deleted file mode 100644
index 9408670..0000000
--- a/db/System.cs
+++ /dev/null
@@ -1,308 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Text;
-using System.Threading;
-using System.Diagnostics;
-
-using Optional;
-using System.Diagnostics.CodeAnalysis;
-
-namespace db
-{
-
- struct TimedAction : IComparable
- {
- public long when;
- public Act act;
-
- public TimedAction( long when, Act act )
- {
- this.when = when;
- this.act = act;
- }
-
- public int CompareTo( TimedAction other )
- {
- return when.CompareTo( other.when );
- }
-
- public override bool Equals( object obj )
- {
- return obj is TimedAction action &&
- when == action.when &&
- EqualityComparer.Default.Equals( act, action.act );
- }
-
- public override int GetHashCode()
- {
- var hc = when.GetHashCode() ^ act.GetHashCode();
- return hc;
- }
- }
-
- public class SystemCfg : lib.Config
- {
- public readonly float Cores = 1;
- }
-
- public class System where T : IID
- {
- //public static System Current => s_system;
-
- public SemaphoreSlim ActsExist => m_actsExist;
- public DB DB { get; private set; }
-
- public bool Running { get; private set; }
-
- public System( res.Ref cfg, DB db )
- {
- m_cfg = cfg;
- DB = db;
-
- var procCount = Environment.ProcessorCount;
-
- //Exact comparison
- if( m_cfg.res.Cores != 0.0f )
- {
- //If its less than 1, then use it as a multiplier
- if( m_cfg.res.Cores < 0.0f )
- {
- procCount = Environment.ProcessorCount - (int)m_cfg.res.Cores;
- }
- else if( m_cfg.res.Cores < 1.0f )
- {
- procCount = (int)( (float)Environment.ProcessorCount * m_cfg.res.Cores );
- }
- else
- {
- procCount = (int)m_cfg.res.Cores;
- }
- }
-
- log.info( $"Running {procCount} cores out of a total cores {Environment.ProcessorCount} via a config Cores value of {m_cfg.res.Cores}" );
-
- Processor[] procs = new Processor[procCount];
-
- for( var i = 0; i < procCount; ++i )
- {
- var proc = new Processor( db, this );
-
- procs[i] = proc;
- }
-
- m_processors = m_processors.AddRange( procs );
-
- Running = true;
-
- }
-
-
- public void forcedThisTick( Act act )
- {
- m_current.Add( act );
-
- m_actsExist.Release();
- }
-
- public void next( Act act )
- {
- m_next.Add( act );
- }
-
- //Most things dont need accurate next frame processing, so split them between the next frame N frames
- const double s_variance = 1.0 / 15.0;
-
- public void future( Act act, double future, double maxVariance = s_variance )
- {
- //m_actions.Add( act );
-
- var variance = m_rand.NextDouble() * maxVariance;
-
- var nextTime = future + variance;
-
- if( nextTime < 1.0 / 60.0 )
- {
- next( act );
- return;
- }
-
- var ts = TimeSpan.FromSeconds( nextTime );
-
- var tsTicks = ts.Ticks;
-
- // @@@ TIMING Should we use a fixed time at the front of the frame for this?
- var ticks = tsTicks + DateTime.Now.Ticks;
-
- var ta = new TimedAction( ticks, act );
-
- var newFuture = m_futureActions.Add( ta );
-
- Interlocked.Exchange( ref m_futureActions, newFuture );
-
- }
-
- public void start()
- {
- int count = 0;
- foreach( var p in m_processors )
- {
- var start = new ThreadStart( p.run );
-
- var th = new Thread( start );
- th.Name = $"Processor_{count}";
-
- th.Start();
-
- ++count;
- }
- }
-
- public void tick()
- {
- //Debug.Assert( m_current.IsEmpty );
-
- addTimedActions();
-
- var current = m_current;
- m_current = m_next;
- m_next = current;
-
- while( !m_current.IsEmpty )
- {
- m_actsExist.Release();
- }
-
-
- /*
- foreach( var proc in m_processors )
- {
- //Debug.Assert( proc.State == State.Waiting );
-
- proc.kick();
- }
- */
- }
-
- /*
- public void wait_blah( int targetMs, int maxMs )
- {
- var done = 0;
-
- var start = DateTime.Now;
- var delta = start - start;
-
- while( done < m_processors.Count && delta.TotalMilliseconds < maxMs )
- {
- done = 0;
-
- foreach( var proc in m_processors )
- {
- if( proc.State != State.Active )
- {
- ++done;
- }
- }
-
- delta = DateTime.Now - start;
- }
-
- if( done != m_processors.Count )
- {
- log.warn( $"Processing took significantly too long {delta.TotalSeconds}sec." );
-
- foreach( var proc in m_processors )
- {
- Act debugAct = proc.DebugCurrentAct;
-
- if( proc.State == State.Active )
- {
- log.warn( $"Proc is still running\n{debugAct.Path}({debugAct.Line}): In method {debugAct.Member}" );
-
- // @@@ TODO Should we kill the procedure? Let it continue to run?
- }
- }
- }
-
- if( delta.TotalMilliseconds > targetMs )
- {
- log.warn( $"Missed our target {delta.TotalMilliseconds} framerate." );
- }
-
- }
- //*/
-
- public void addTimedActions()
- {
- var sortedFutureActions = m_futureActions.Sort();
-
- var future = TimeSpan.FromMilliseconds( 33.33333 );
-
- var time = DateTime.Now + future;
-
- foreach( var action in sortedFutureActions )
- {
- if( action.when < time.Ticks )
- {
- next( action.act );
-
- var newActions = m_futureActions.Remove( action );
-
- Interlocked.Exchange( ref m_futureActions, newActions );
-
- }
- else
- {
- break;
- }
- }
- }
-
- public void stopRunning()
- {
- Running = false;
- }
-
-
-
-
- internal Option getNextAct()
- {
- if( m_current.TryTake( out Act res ) )
- {
- return res.Some();
- }
-
- m_actsExist.Wait();
-
- return Option.None();
- }
-
- res.Ref m_cfg;
-
- SemaphoreSlim m_actsExist = new SemaphoreSlim( 0 );
-
- Random m_rand = new Random();
-
- ConcurrentBag m_current = new ConcurrentBag();
- ConcurrentBag m_next = new ConcurrentBag();
-
- // @@ TODO Keep an eye on the timing of this.
- ImmutableList m_futureActions = ImmutableList.Empty;
-
- /*
- TimedAction[] m_sortedFutureActions = new TimedAction[16 * 1024];
- int m_sfaStart = 0;
- int m_sfaEnd = 0;
- */
-
-
-
- ImmutableList> m_processors = ImmutableList>.Empty;
-
- //private static System s_system;
- }
-
-
-}
diff --git a/exp/Exp.cs b/exp/Exp.cs
deleted file mode 100644
index 6a58bab..0000000
--- a/exp/Exp.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-using System.Collections.Immutable;
-using System.Runtime.CompilerServices;
-
-namespace exp;
-
-
-abstract public record class Exp : io.Versioned>
-{
- protected Exp()
- :
- base()
- {
-
- }
-
- abstract public T exec();
-}
-
-public record class ConstantExp( T value ) : Exp
-{
- public override T exec() => value;
-}
-
-public record class VarExp : Exp
-{
-
- public T val = default!;
-
- public VarExp()
- {
- }
-
- public override T exec() => val;
-
- public VarExp set( T newVal )
- {
- return this with { val = newVal };
- }
-}
-
-public ref struct RefHolder
-{
- public T val = default!;
-
- public RefHolder()
- {
- }
-
- public RefHolder( T initial )
- {
- val = initial;
- }
-}
-
-
-/*
-
-public record class Op( EntityId id, Func fn,
- [CallerMemberName] string dbgMethod = "",
- [CallerFilePath] string dbgPath = "",
- [CallerLineNumber] int dbgLine = 0,
- [CallerArgumentExpression("fn")]
- string dbgExp = ""
-) : Exp
-{
- public override T exec()
- {
- var ent = ent.Entity.Get( id );
- if( ent == null )
- throw new System.Exception( $"Op<{typeof(T).Name}>: Entity {id} not found" );
-
- return fn( ent );
- }
-}
-*/
-
-
-public record class StackExp( VarExp BaseVal ) : Exp
-{
- public VarExp ModValue = BaseVal;
-
- public ImmutableArray> Adds = ImmutableArray>.Empty;
- public ImmutableArray> Mults = ImmutableArray>.Empty;
-
- public override T exec()
- {
- return ModValue.exec();
- }
-}
-
-
-
-
-
-
-/// //
-
-
diff --git a/fsm/FSM.cs b/fsm/FSM.cs
deleted file mode 100644
index 95d51a2..0000000
--- a/fsm/FSM.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-using System;
-using System.Runtime.CompilerServices;
-
-
-
-namespace fsm;
-
-
-
-public class Context
-{
-
-}
-
-public class State
- where T : State
- where CTX : Context
-{
- virtual public void onEnter( CTX ctx, State oldState )
- {
- }
-
- virtual public void onExit( CTX ctx, State newState )
- {
- }
-}
-
-public class FSM
- where T : FSM
- where CTX : Context
- where ST : State
-{
- public CTX Context { get; private set; }
- public ST State { get; private set; }
-
- public FSM( CTX context, ST state )
- {
- Context = context;
- State = state;
-
- State.onEnter( Context, state );
- }
-
- public void transition( ST newState, string reason = "",
- [CallerMemberName] string member = "",
- [CallerFilePath] string path = "",
- [CallerLineNumber] int line = 0 )
- {
- log.debug( $"{GetType().Name} switching to {newState.GetType().Name}from {State.GetType().Name} bcs {reason} Code {log.relativePath( path )}:({line}): {member}" );
-
- State.onExit( Context, newState );
- newState.onEnter( Context, State );
- State = newState;
- }
-
-}
-
-/*
-
-Im going to preface this with, I use FSMs everywhere for quite a few things.
-
-*/
diff --git a/imm/Util.cs b/imm/Util.cs
deleted file mode 100644
index 585827a..0000000
--- a/imm/Util.cs
+++ /dev/null
@@ -1,2 +0,0 @@
-using System;
-using System.Collections.Generic;
diff --git a/lib/CodeGen.cs b/lib/CodeGen.cs
deleted file mode 100644
index 1488112..0000000
--- a/lib/CodeGen.cs
+++ /dev/null
@@ -1,182 +0,0 @@
-/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//
-// S H A R P L I B
-//
-/// // (c) 2003..2025
-
-using System;
-using System.IO;
-using System.Xml;
-using System.Collections;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Linq;
-using System.Collections.Immutable;
-using System.Collections.Concurrent;
-using System.Collections.Immutable;
-
-namespace ser;
-
-public record CodeGenConfig : io.Recorded
-{
- // Whitelists (if needed, otherwise rely on attributes/defaults)
- public ImmutableDictionary> WLProps { get; init; } = ImmutableDictionary>.Empty;
- public ImmutableDictionary> WLFields { get; init; } = ImmutableDictionary>.Empty;
-
- // Default member types to process
- public ser.Types TypesDefault { get; init; } = ser.Types.Fields | ser.Types.Props;
-
- // How to handle backing fields (might be less relevant for code gen)
- public BackingFieldNaming Naming { get; init; } = BackingFieldNaming.Regular;
-
- public static CodeGenConfig Default { get; } = new CodeGenConfig();
-}
-
-public record GenMemberMeta(
- MemberInfo Info,
- Type Type,
- string Name, // Name for code generation (usually original)
- bool IsPrimitive,
- bool IsCollection,
- Type? CollectionElementType,
- bool HasDo,
- bool HasDont
-);
-
-public record TypeStructureInfo(
- Type Type,
- List Members,
- bool IsValueType,
- bool IsCollection
-);
-
-public class TypeStructureAnalyzer
-{
- private readonly ConcurrentDictionary _cache = new();
- private readonly CodeGenConfig _cfg;
-
- public TypeStructureAnalyzer( CodeGenConfig cfg ) => _cfg = cfg;
-
- public TypeStructureInfo Get( Type type ) => _cache.GetOrAdd( type, BuildTypeInfo );
-
- private TypeStructureInfo BuildTypeInfo( Type type )
- {
- var members = new List();
- var typesTodo = type.GetCustomAttribute( true )?.Types ?? _cfg.TypesDefault;
- bool doFields = typesTodo.HasFlag( ser.Types.Fields );
- bool doProps = typesTodo.HasFlag( ser.Types.Props );
-
- // Track processed names to avoid duplicates (e.g., field + prop)
- var processedNames = new HashSet();
-
- // Process Properties First (often preferred interface)
- if( doProps )
- {
- foreach( var pi in refl.GetAllProperties( type ) )
- {
- if( ProcessMember( pi, false, false, new HashSet(), false, members ) )
- {
- processedNames.Add( pi.Name );
- }
- }
- }
-
- // Process Fields, avoiding those already covered by properties
- if( doFields )
- {
- foreach( var fi in refl.GetAllFields( type ) )
- {
- var (isBacking, propName) = IsBackingField( fi );
- string nameToTest = isBacking ? propName : fi.Name;
-
- if( !processedNames.Contains( nameToTest ) )
- {
- if( ProcessMember( fi, false, false, new HashSet(), false, members ) )
- {
- processedNames.Add( nameToTest );
- }
- }
- }
- }
-
- return new TypeStructureInfo(
- type,
- members,
- type.IsValueType,
- typeof( IEnumerable ).IsAssignableFrom( type ) && type != typeof( string )
- );
- }
-
- private bool ProcessMember( MemberInfo mi, bool filter, bool doImpls, HashSet whitelist, bool isImm, List members )
- {
- var (hasDo, hasDont, propName) = GetMemberAttributes( mi, out var actualMiForAtts );
-
- if( hasDont )
- return false;
- if( mi.GetCustomAttribute( true ) != null )
- return false;
- if( mi.Name.Contains( "k__BackingField" ) && !propName.Any() )
- return false; // Skip if backing but no prop found
-
- string name = string.IsNullOrEmpty( propName ) ? mi.Name : propName;
-
- // Add filtering logic if needed (based on whitelist, etc.)
-
- var type = ( mi is FieldInfo fi ) ? fi.FieldType : ( (PropertyInfo)mi ).PropertyType;
- bool isCollection = typeof( IEnumerable ).IsAssignableFrom( type ) && type != typeof( string );
- Type? elementType = isCollection ? GetElementType( type ) : null;
- bool isPrimitive = Type.GetTypeCode( type ) != TypeCode.Object && !isCollection;
-
- members.Add( new GenMemberMeta(
- mi, type, name, isPrimitive, isCollection, elementType, hasDo, hasDont
- ) );
- return true;
- }
-
- private (bool, string) IsBackingField( FieldInfo fi )
- {
- if( fi.Name.StartsWith( "<" ) && fi.Name.EndsWith( "BackingField" ) )
- {
- var gtIndex = fi.Name.IndexOf( '>' );
- if( gtIndex > 1 )
- {
- return (true, fi.Name.Substring( 1, gtIndex - 1 ));
- }
- }
- return (false, "");
- }
-
- private (bool hasDo, bool hasDont, string propName) GetMemberAttributes( MemberInfo mi, out MemberInfo actualMi )
- {
- actualMi = mi;
- string propName = "";
- if( mi is FieldInfo fi && IsBackingField( fi ).Item1 )
- {
- propName = IsBackingField( fi ).Item2;
- var propInfo = mi.DeclaringType?.GetProperty( propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );
- if( propInfo != null )
- actualMi = propInfo;
- }
- else if( mi is PropertyInfo )
- {
- propName = mi.Name;
- }
-
- return (
- actualMi.GetCustomAttribute() != null,
- actualMi.GetCustomAttribute() != null,
- propName
- );
- }
-
- private Type GetElementType( Type collectionType )
- {
- if( collectionType.IsArray )
- return collectionType.GetElementType()!;
- if( collectionType.IsGenericType )
- return collectionType.GetGenericArguments().Last(); // Usually last (e.g., List, Dict)
- return typeof( object ); // Fallback
- }
-
- // Add GetFilters and FilterField if needed, or simplify as above
-}
diff --git a/lib/CodeGenerator.cs b/lib/CodeGenerator.cs
deleted file mode 100644
index 2b08984..0000000
--- a/lib/CodeGenerator.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System.Text;
-using System.Collections.Generic;
-using System;
-using System.Linq;
-
-namespace ser;
-
-public abstract class CodeGenerator
-{
- protected StringBuilder _sb = new StringBuilder();
- protected int _indent = 0;
- protected TypeStructureAnalyzer _analyzer;
- protected CodeGenConfig _config;
- protected HashSet _generatedTypes = new(); // Track to avoid re-generating
-
- public CodeGenerator( CodeGenConfig config )
- {
- _config = config;
- _analyzer = new TypeStructureAnalyzer( config );
- }
-
- // Main entry point
- public string Generate( Type type, string ns = "GeneratedCode" )
- {
- _sb.Clear();
- WriteLine( "using System;" );
- WriteLine( "using System.Collections.Generic;" );
- WriteLine( "using System.Linq;" );
- WriteLine( "" );
- WriteLine( $"namespace {ns};" );
- WriteLine( "" );
- GenerateForType( type );
- return _sb.ToString();
- }
-
- // Core generation logic - needs to be recursive for dependencies
- protected virtual void GenerateForType( Type type )
- {
- if( type == null || !CanGenerateFor( type ) || _generatedTypes.Contains( type ) )
- return;
-
- _generatedTypes.Add( type );
- var info = _analyzer.Get( type );
-
- // Generate dependencies first
- foreach( var member in info.Members )
- {
- GenerateForType( member.Type );
- if( member.IsCollection && member.CollectionElementType != null )
- {
- GenerateForType( member.CollectionElementType );
- }
- }
-
- // Generate the actual code
- GenerateClassHeader( info );
- BeginBlock();
- GenerateClassBody( info );
- EndBlock();
- }
-
- // Abstract methods to be implemented by specific generators
- protected abstract void GenerateClassHeader( TypeStructureInfo info );
- protected abstract void GenerateClassBody( TypeStructureInfo info );
- protected abstract bool CanGenerateFor( Type type ); // Check if we should generate for this type
-
- // Helper methods
- protected void WriteLine( string line = "" ) => _sb.AppendLine( new string( '\t', _indent ) + line );
- protected void BeginBlock() { WriteLine( "{" ); _indent++; }
- protected void EndBlock() { _indent--; WriteLine( "}" ); }
- protected string GetTypeName( Type t ) => t.IsGenericType
- ? $"{t.Name.Split( '`' )[0]}<{string.Join( ", ", t.GetGenericArguments().Select( GetTypeName ) )}>"
- : t.Name; // Basic handling, needs improvement for full names/namespaces
-}
diff --git a/lib/SerializableDictionary.cs_bad b/lib/SerializableDictionary.cs_bad
deleted file mode 100644
index a16151a..0000000
--- a/lib/SerializableDictionary.cs_bad
+++ /dev/null
@@ -1,166 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Xml.Serialization;
-using System.Xml;
-using System.Runtime.Serialization;
-using System.Runtime.Serialization.Formatters.Binary;
-using System.IO;
-using System.Security.Permissions;
-
-namespace lib
-{
- [Serializable]
- public class SerializableDictionary: Dictionary, IXmlSerializable, ISerializable
- {
- #region Constants
- private const string DictionaryNodeName = "Dictionary";
- private const string ItemNodeName = "Item";
- private const string KeyNodeName = "Key";
- private const string ValueNodeName = "Value";
- #endregion
- #region Constructors
- public SerializableDictionary()
- {
- }
-
- public SerializableDictionary( IDictionary dictionary )
- : base( dictionary )
- {
- }
-
- public SerializableDictionary( IEqualityComparer comparer )
- : base( comparer )
- {
- }
-
- public SerializableDictionary( int capacity )
- : base( capacity )
- {
- }
-
- public SerializableDictionary( IDictionary dictionary, IEqualityComparer comparer )
- : base( dictionary, comparer )
- {
- }
-
- public SerializableDictionary( int capacity, IEqualityComparer comparer )
- : base( capacity, comparer )
- {
- }
-
- #endregion
- #region ISerializable Members
-
- protected SerializableDictionary( SerializationInfo info, StreamingContext context )
- {
- int itemCount = info.GetInt32("ItemCount");
- for( int i = 0; i < itemCount; i++ )
- {
- KeyValuePair kvp = (KeyValuePair)info.GetValue(String.Format( $"Item{i}" ), typeof(KeyValuePair));
- this.Add( kvp.Key, kvp.Value );
- }
- }
-
-
- //[SecurityPermission( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter )]
- void ISerializable.GetObjectData( SerializationInfo info, StreamingContext context )
- {
- info.AddValue( "ItemCount", this.Count );
- int itemIdx = 0;
- foreach( KeyValuePair kvp in this )
- {
- info.AddValue( String.Format( $"Item{itemIdx}" ), kvp, typeof( KeyValuePair ) );
- itemIdx++;
- }
- }
-
- #endregion
- #region IXmlSerializable Members
-
- void IXmlSerializable.WriteXml( System.Xml.XmlWriter writer )
- {
- //writer.WriteStartElement(DictionaryNodeName);
- foreach( KeyValuePair kvp in this )
- {
- writer.WriteStartElement( ItemNodeName );
- writer.WriteStartElement( KeyNodeName );
- KeySerializer.Serialize( writer, kvp.Key );
- writer.WriteEndElement();
- writer.WriteStartElement( ValueNodeName );
- ValueSerializer.Serialize( writer, kvp.Value );
- writer.WriteEndElement();
- writer.WriteEndElement();
- }
- //writer.WriteEndElement();
- }
-
- void IXmlSerializable.ReadXml( System.Xml.XmlReader reader )
- {
- if( reader.IsEmptyElement )
- {
- return;
- }
-
- // Move past container
- if( !reader.Read() )
- {
- throw new XmlException( "Error in Deserialization of Dictionary" );
- }
-
- //reader.ReadStartElement(DictionaryNodeName);
- while( reader.NodeType != XmlNodeType.EndElement )
- {
- reader.ReadStartElement( ItemNodeName );
- reader.ReadStartElement( KeyNodeName );
- TKey key = (TKey)KeySerializer.Deserialize(reader);
- reader.ReadEndElement();
- reader.ReadStartElement( ValueNodeName );
- TVal value = (TVal)ValueSerializer.Deserialize(reader);
- reader.ReadEndElement();
- reader.ReadEndElement();
- this.Add( key, value );
- reader.MoveToContent();
- }
- //reader.ReadEndElement();
-
- reader.ReadEndElement(); // Read End Element to close Read of containing node
- }
-
- System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
- {
- return null;
- }
-
- #endregion
- #region Private Properties
- protected XmlSerializer ValueSerializer
- {
- get
- {
- if( valueSerializer == null )
- {
- valueSerializer = new XmlSerializer( typeof( TVal ) );
- }
- return valueSerializer;
- }
- }
-
- private XmlSerializer KeySerializer
- {
- get
- {
- if( keySerializer == null )
- {
- keySerializer = new XmlSerializer( typeof( TKey ) );
- }
- return keySerializer;
- }
- }
- #endregion
- #region Private Members
- private XmlSerializer keySerializer = null;
- private XmlSerializer valueSerializer = null;
- #endregion
- }
-}
diff --git a/lib/VersionFormatter.cs_bad b/lib/VersionFormatter.cs_bad
deleted file mode 100644
index 815a1fe..0000000
--- a/lib/VersionFormatter.cs_bad
+++ /dev/null
@@ -1,677 +0,0 @@
-using System;
-using System.IO;
-using System.Reflection;
-using System.Collections;
-using System.Diagnostics;
-//using System.Globalization;
-//using System.ComponentModel;
-using System.Runtime.Serialization;
-
-namespace lib
-{
- ///
- ///
- ///
- public class VersionFormatter: IFormatter
- {
- public enum ETypes
- {
- Array,
- Int32,
- Ref,
- Object,
- EndObject,
- Single,
- Double,
- Char,
- String,
- Boolean,
- EndStream,
- }
-
-
- public VersionFormatter()
- {
- //
- // TODO: Add constructor logic here
- //
- }
-
-
- #region Useless
- public ISurrogateSelector SurrogateSelector
- {
- get
- {
- return null;
- }
-
- set
- {
- }
- }
-
- public SerializationBinder Binder
- {
- get
- {
- return null;
- }
-
- set
- {
- }
- }
-
- public StreamingContext Context
- {
- get
- {
- return new StreamingContext();
- }
-
- set
- {
- }
- }
- #endregion Useless
-
- Queue m_objectsToBeDeserialized = new Queue();
- Hashtable m_alreadyDeserialzied = new Hashtable();
- //int m_GUID = 0;
-
- #region Serialize
- public void Serialize( Stream stream, object obj )
- {
- //Default is 4k
- //BufferedStream bufStream = new BufferedStream( stream );
-
- BinaryWriter writer = new BinaryWriter( stream );
-
- writeObject( writer, obj );
-
- while( m_objectsToBeDeserialized.Count != 0 )
- {
- object objToDes = m_objectsToBeDeserialized.Dequeue();
-
- writeObject( writer, objToDes );
- }
-
- writer.Write( (char)ETypes.EndStream );
- }
-
- void writeRefAndSched( BinaryWriter writer, object obj )
- {
- //if( m_alreadyDeserialzied[ obj.GetType().GetArrayRank(
-
- if( obj == null )
- {
- writer.Write( 0 );
- return;
- }
-
-
- //Now write the address.
- //Bad bad. Need to do this correctly.
- int objRef = obj.GetHashCode();
- writer.Write( objRef );
-
- if( m_alreadyDeserialzied[obj] == null )
- {
- m_alreadyDeserialzied[obj] = obj;
- m_objectsToBeDeserialized.Enqueue( obj );
- }
- }
-
- void dispatchWrite( BinaryWriter writer, object parentObj, FieldInfo fi )
- {
- string typeName = fi.FieldType.Name;
-
- string name = fi.Name;
-
- if( fi.IsNotSerialized )
- {
- return;
- }
-
- if( fi.FieldType.IsArray )
- {
- writer.Write( (char)ETypes.Array );
- writer.Write( name.GetHashCode() );
-
- writeArray( writer, (Array)fi.GetValue( parentObj ) );
- }
- else if( ( fi.FieldType.IsClass || fi.FieldType.IsInterface ) && typeName != "String" )
- {
- writer.Write( (char)ETypes.Ref );
- writer.Write( name.GetHashCode() );
-
- writeRefAndSched( writer, fi.GetValue( parentObj ) );
- }
- else if( fi.FieldType.IsEnum )
- {
- writer.Write( (char)ETypes.Int32 );
- writer.Write( name.GetHashCode() );
-
- write( writer, Convert.ToInt32( fi.GetValue( parentObj ) ) );
- }
- else
- {
- switch( typeName )
- {
- case "Int32":
- writer.Write( (char)ETypes.Int32 );
- writer.Write( name.GetHashCode() );
-
- write( writer, Convert.ToInt32( fi.GetValue( parentObj ) ) );
- break;
- case "Single":
- writer.Write( (char)ETypes.Single );
- writer.Write( name.GetHashCode() );
-
- write( writer, Convert.ToSingle( fi.GetValue( parentObj ) ) );
- break;
- case "Double":
- writer.Write( (char)ETypes.Double );
- writer.Write( name.GetHashCode() );
-
- write( writer, Convert.ToDouble( fi.GetValue( parentObj ) ) );
- break;
- case "Char":
- writer.Write( (char)ETypes.Char );
- writer.Write( name.GetHashCode() );
-
- write( writer, Convert.ToChar( fi.GetValue( parentObj ) ) );
- break;
- case "String":
- writer.Write( (char)ETypes.String );
- writer.Write( name.GetHashCode() );
-
- write( writer, Convert.ToString( fi.GetValue( parentObj ) ) );
- break;
- case "Boolean":
- writer.Write( (char)ETypes.Boolean );
- writer.Write( name.GetHashCode() );
-
- writer.Write( Convert.ToBoolean( fi.GetValue( parentObj ) ) );
- break;
- default:
- Console.WriteLine( "VersionFormatter does not understand type " + typeName );
- break;
- }
- }
- }
-
- void writeArray( BinaryWriter writer, Array array )
- {
- if( array == null )
- {
- writer.Write( (int)-1 );
- return;
- }
-
- writer.Write( array.Length );
-
- foreach( object obj in array )
- {
- writeRefAndSched( writer, obj );
- }
- }
-
- void getAllFields( object obj, ArrayList list )
- {
- Type t = obj.GetType();
-
- while( t != null )
- {
- FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly );
- list.AddRange( fiArr );
-
- t = t.BaseType;
- }
- }
-
-
- void writeObject( BinaryWriter writer, object obj )
- {
- Type objType = obj.GetType();
-
- writer.Write( (char)ETypes.Object );
- writer.Write( objType.FullName );
-
- int objRef = obj.GetHashCode();
- writer.Write( objRef );
-
- ArrayList list = new ArrayList();
-
- getAllFields( obj, list );
-
- foreach( FieldInfo fi in list )
- {
- dispatchWrite( writer, obj, fi );
- }
-
- writer.Write( (char)ETypes.EndObject );
- }
-
- void write( BinaryWriter wr, TType val )
- {
- //wr.Write( val );
- }
-
- /*
- void writeInt( BinaryWriter writer, int val )
- {
- writer.Write( val );
- }
-
- void writeSingle( BinaryWriter writer, float val )
- {
- writer.Write( val );
- }
-
- void writeDouble( BinaryWriter writer, double val )
- {
- writer.Write( val );
- }
-
- void writeChar( BinaryWriter writer, char val )
- {
- writer.Write( val );
- }
-
- void writeString( BinaryWriter writer, string val )
- {
- writer.Write( val );
- }
-
- void writeBool( BinaryWriter writer, bool val )
- {
- writer.Write( val );
- }
- */
- #endregion Serialize
-
-
- #region Deserialize
-
- class Fixup
- {
- public Fixup( int guid, object obj, FieldInfo fi )
- {
- m_guid = guid;
- m_obj = obj;
- m_fi = fi;
- }
-
- public Fixup( int guid, object obj, int index )
- {
- m_guid = guid;
- m_obj = obj;
- m_index = index;
- }
-
- public readonly int m_guid = 0;
- public readonly object m_obj = null;
-
- public readonly FieldInfo m_fi = null;
- public readonly int m_index= -1;
-
- }
-
- Hashtable m_mapGUIDToObject = new Hashtable();
- ArrayList m_fixupList = new ArrayList();
-
- ArrayList m_desObjects = new ArrayList();
-
- public object Deserialize( Stream stream )
- {
- BinaryReader reader = new BinaryReader( stream );
-
- object objRoot = null;
-
- //Read in the first object.
- {
- ETypes type = (ETypes)reader.ReadChar();
-
- Debug.Assert( type == ETypes.Object );
-
- objRoot = readObject( reader );
-
- m_desObjects.Add( objRoot );
- }
-
- bool readObjects = true;
-
- while( readObjects )
- {
- ETypes type = (ETypes)reader.ReadChar();
-
- Debug.Assert( type == ETypes.Object || type == ETypes.EndStream );
-
- if( type == ETypes.Object )
- {
- object obj = readObject( reader );
-
- m_desObjects.Add( obj );
- }
- else
- {
- Debug.Assert( type == ETypes.EndStream );
-
- readObjects = false;
- }
- }
-
- foreach( Fixup fu in m_fixupList )
- {
- //Fixup fix = m_fixups[
-
- object obj = m_mapGUIDToObject[ fu.m_guid ];
-
- if( obj != null )
- {
- if( fu.m_fi != null )
- {
- fu.m_fi.SetValue( fu.m_obj, obj );
- }
- else
- {
- Debug.Assert( fu.m_index >= 0 );
-
- object []array = (object [])fu.m_obj;
-
- array[fu.m_index] = obj;
- }
- }
- else
- {
- Console.WriteLine( "Obj to ref is null." );
- }
- }
-
- foreach( object obj in m_desObjects )
- {
- if( typeof( IDeserializationCallback ).IsAssignableFrom( obj.GetType() ) )
- {
- IDeserializationCallback desCB = (IDeserializationCallback)obj;
-
- if( desCB != null )
- {
- desCB.OnDeserialization( this );
- }
- }
- }
-
- return objRoot;
- }
-
-
-
- bool dispatchRead( BinaryReader reader, object obj, Hashtable ht )
- {
-
- //Read the type
- ETypes type = (ETypes)reader.ReadChar();
-
- if( type == ETypes.EndObject )
- {
- return false;
- }
-
- int nameHash = reader.ReadInt32();
-
- FieldInfo fi = (FieldInfo)ht[ nameHash ];
-
- if( fi == null )
- {
- Console.WriteLine( "Field no longer exists" );
- }
-
- try
- {
- switch( type )
- {
- case ETypes.Array:
- readArray( reader, obj, fi );
- break;
- case ETypes.Int32:
- readInt( reader, obj, fi );
- break;
- case ETypes.Single:
- readSingle( reader, obj, fi );
- break;
- case ETypes.Double:
- readDouble( reader, obj, fi );
- break;
- case ETypes.Char:
- readChar( reader, obj, fi );
- break;
- case ETypes.Boolean:
- readBool( reader, obj, fi );
- break;
- case ETypes.String:
- readString( reader, obj, fi );
- break;
- case ETypes.Ref:
- readRef( reader, obj, fi );
- break;
- case ETypes.Object:
- readObject( reader );
- break;
- default:
- Debug.Fail( "Unknown type on read." );
- break;
- }
- }
- catch( Exception ex )
- {
- Console.WriteLine( "Exception: " + ex.Message );
- Console.WriteLine( "Stack: " + ex.StackTrace );
- }
-
-
- return true;
- }
-
- object createObject( string objTypeName )
- {
- Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
-
- foreach( Assembly a in ass )
- {
- Type t = a.GetType( objTypeName );
-
- if( t != null )
- {
- object obj = FormatterServices.GetUninitializedObject( t );
-
- if( obj != null )
- {
- return obj;
- }
- }
- }
-
- return null;
- }
-
-
- object readObject( BinaryReader reader )
- {
- //ETypes type = (ETypes)reader.ReadChar();
-
- //Debug.Assert( type == ETypes.Object, "Expecting type Object" );
-
- string objTypeName = reader.ReadString();
- int objGUID = reader.ReadInt32();
-
- try
- {
- object obj = createObject( objTypeName );
-
- m_mapGUIDToObject[objGUID] = obj;
-
- ArrayList list = new ArrayList();
- Hashtable ht = new Hashtable();
-
- if( obj != null )
- {
- getAllFields( obj, list );
-
- foreach( FieldInfo fi in list )
- {
- ht[fi.Name.GetHashCode()] = fi;
- }
- }
-
- while( dispatchRead( reader, obj, ht ) )
- {
- }
-
- return obj;
- }
- catch( Exception ex )
- {
- Console.WriteLine( "Exception: " + ex.Message );
- }
-
- return null;
- }
-
- void readArray( BinaryReader reader, object obj, FieldInfo fi )
- {
- int length = reader.ReadInt32();
-
- if( length < 0 )
- {
- if( fi == null )
- return;
-
- fi.SetValue( obj, null );
-
- return;
- }
-
- object[] array = new object[length];
-
- if( fi != null )
- {
- fi.SetValue( obj, array );
- }
-
- for( int i = 0; i < length; ++i )
- {
- int val = reader.ReadInt32();
-
- //m_fixups[ val ] = new Fixup( obj, fi );
-
- if( fi != null )
- {
- m_fixupList.Add( new Fixup( val, array, i ) );
- }
- }
- }
-
- void readRef( BinaryReader reader, object obj, FieldInfo fi )
- {
- int val = reader.ReadInt32();
-
- //m_fixups[ val ] = new Fixup( obj, fi );
-
- m_fixupList.Add( new Fixup( val, obj, fi ) );
- }
-
- void readInt( BinaryReader reader, object obj, FieldInfo fi )
- {
- int val = reader.ReadInt32();
-
- if( fi == null )
- return;
-
- if( !fi.FieldType.IsEnum )
- {
- fi.SetValue( obj, val );
- }
- else
- {
- object enumVal = Enum.Parse( fi.FieldType, val.ToString() );
- fi.SetValue( obj, Convert.ChangeType( enumVal, fi.FieldType ) );
- }
-
- }
-
- void readSingle( BinaryReader reader, object obj, FieldInfo fi )
- {
- float val = reader.ReadSingle();
-
- if( fi == null )
- return;
-
- fi.SetValue( obj, val );
- }
-
- void readDouble( BinaryReader reader, object obj, FieldInfo fi )
- {
- double val = reader.ReadDouble();
-
- if( fi == null )
- return;
-
- fi.SetValue( obj, val );
- }
-
- void readChar( BinaryReader reader, object obj, FieldInfo fi )
- {
- char val = reader.ReadChar();
-
- if( fi == null )
- return;
-
- fi.SetValue( obj, val );
- }
-
- void readString( BinaryReader reader, object obj, FieldInfo fi )
- {
- string val = reader.ReadString();
-
- if( fi == null )
- return;
-
- fi.SetValue( obj, val );
- }
-
- void readBool( BinaryReader reader, object obj, FieldInfo fi )
- {
- bool val = reader.ReadBoolean();
-
- if( fi == null )
- return;
-
- fi.SetValue( obj, val );
- }
-
- #endregion Deserialize
-
-
- }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/XmlFormatter.cs_bad b/lib/XmlFormatter.cs_bad
deleted file mode 100644
index 6573732..0000000
--- a/lib/XmlFormatter.cs_bad
+++ /dev/null
@@ -1,1094 +0,0 @@
-using System;
-using System.IO;
-using System.Xml;
-using System.Runtime.Serialization;
-//using System.Web.Configuration;
-using System.Collections;
-using System.Collections.Generic;
-
-
-using System.Reflection;
-//using System.Collections;
-//using System.Diagnostics;
-//using System.Globalization;
-//using System.ComponentModel;
-
-
-namespace lib
-{
- //Old, use 2 now.
- class XmlFormatter_BAD: IFormatter
- {
- StreamingContext m_context;
- //SerializationMode m_mode;
- //KnownTypeCollection known_types;
- //IDataContractSurrogate m_surrogate;
- //int m_maxItems;
-
- public XmlFormatter()
- {
- }
-
- /*
- public XmlFormatter( SerializationMode mode )
- {
- m_mode = mode;
- }
-
- public XmlFormatter( StreamingContext context )
- {
- m_context = context;
- }
-
- public XmlFormatter( SerializationMode mode,
- StreamingContext context )
- {
- m_mode = mode;
- m_context = context;
- }
- */
-
- //public XmlFormatter (SerializationMode mode,
- // StreamingContext context, KnownTypeCollection knownTypes)
- //{
- //}
-
- SerializationBinder IFormatter.Binder
- {
- get { throw new NotImplementedException(); }
- set { throw new NotImplementedException(); }
- }
-
- ISurrogateSelector IFormatter.SurrogateSelector
- {
- get { throw new NotImplementedException(); }
- set { throw new NotImplementedException(); }
- }
-
- public StreamingContext Context
- {
- get { return m_context; }
- set { m_context = value; }
- }
-
-
- /*
- public KnownTypeCollection KnownTypes {
- get { return known_types; }
- }
-
- public int MaxItemsInObjectGraph {
- get { return m_maxItems; }
- set { m_maxItems= value; }
- }
- */
-
-
- object IFormatter.Deserialize( Stream stream )
- {
- return Deserialize( stream, null );
- }
-
- public object Deserialize( Stream stream, Type type )
- {
- XmlTextReader reader = new XmlTextReader( stream );
-
- return Deserialize( reader, type );
- }
-
- public object Deserialize( XmlReader reader, Type type )
- {
- return Deserialize( reader, type, false );
- }
-
- public object Deserialize( XmlReader reader, Type type, bool readContentOnly )
- {
- reader.Read();
-
- XmlDocument doc = new XmlDocument();
-
- doc.Load( reader );
-
- return Deserialize( doc.DocumentElement );
- }
-
- ConstructorInfo getNoParamCons( ConstructorInfo[] ciArr )
- {
- foreach( ConstructorInfo ci in ciArr )
- {
- if( ci.GetParameters().Length == 0 )
- {
- return ci;
- }
- }
-
- return null;
- }
-
- private static FormatterConverter s_conv = new FormatterConverter();
-
- private Dictionary m_alreadySerialized = new Dictionary();
-
- public object Deserialize( XmlElement elem )
- {
- string strType = elem.GetAttribute( "t" );
-
- return Deserialize( elem, strType );
- }
-
- public object Deserialize( XmlElement elem, string strType )
- {
- Type type = Type.GetType( strType );
-
- MemberInfo[] miArr = FormatterServices.GetSerializableMembers( type );
-
- object obj = Activator.CreateInstance( type );
-
-
- /*
- object obj = FormatterServices.GetUninitializedObject( type );
-
-
- ConstructorInfo[] ciArr = obj.GetType().GetConstructors();
-
- ConstructorInfo ci = getNoParamCons( ciArr );
-
- if( ci == null )
- return null;
-
- obj = ci.Invoke( null );
- */
-
- for( int i = 0; i < miArr.Length; ++i )
- {
- FieldInfo fi = (FieldInfo)miArr[ i ];
-
- XmlNodeList nodeList = elem.GetElementsByTagName( fi.Name );
-
- if( nodeList.Count == 1 )
- {
- Type t = fi.FieldType;
-
- TypeCode tc = Type.GetTypeCode( t );
-
- XmlElement child = (XmlElement)nodeList[ 0 ];
-
- object childObj = null;
-
- if( tc != TypeCode.Object || fi.FieldType.FullName == "System.String" )
- {
- childObj = s_conv.Convert( child.GetAttribute( "v" ), fi.FieldType );
- }
- else
- {
- if( !t.IsArray )
- {
- string refStr = child.GetAttribute( "ref" );
- int refInt = Convert.ToInt32( refStr );
-
- if( child.HasAttribute( "t" ) )
- {
- childObj = Deserialize( child );
-
- m_alreadySerialized[refInt] = childObj;
- }
- else
- {
- childObj = m_alreadySerialized[refInt];
- }
- }
- else
- {
- //FormatterServices.GetUninitializedObject()
-
- int length = s_conv.ToInt32( child.GetAttribute( "c" ) );
-
- string elemType = child.GetAttribute( "t" );
-
- Array arr = Array.CreateInstance( t.GetElementType(), length );
-
- XmlNodeList arrNodeList = child.ChildNodes;
-
- for( int iElems = 0; iElems < arr.Length; ++iElems )
- {
- XmlElement arrElem = (XmlElement)arrNodeList.Item( iElems );
-
- arr.SetValue( Deserialize( arrElem, elemType ), iElems );
- }
- }
- }
-
- fi.SetValue( obj, childObj );
- }
- else
- {
- if( nodeList.Count == 0 )
- {
- // Should be
-
- //object obj2 = fi.GetRawConstantValue();
- }
- else //More than 1.
- {
- //log.error( "Too many fields named the same thing" );
- }
- }
- }
-
- //FieldInfo fi = (FieldInfo)miArr[0];
-
- //ConstructorInfo ci = fi.FieldType.TypeInitializer;
-
- //ci.Invoke( null );
-
- return obj;
- }
-
-
- /*
- public T Deserialize (Stream stream)
- {
- return (T) Deserialize (XmlReader.Create (stream), typeof (T));
- }
-
- public T Deserialize (XmlReader reader)
- {
- return (T) Deserialize (reader, typeof (T), false);
- }
-
- public T Deserialize (XmlReader reader, bool readContentOnly)
- {
- return (T) Deserialize (reader, typeof (T), readContentOnly);
- }
- */
-
- public void Serialize( Stream stream, object graph )
- {
- /*
- XmlWriterSettings settings = new XmlWriterSettings();
-
- settings.Indent = true;
-
- Serialize( XmlWriter.Create( stream, settings ), graph );
- */
-
- XmlTextWriter writer = new XmlTextWriter( stream, null );
-
- writer.Formatting = Formatting.Indented;
-
- Serialize( writer, graph );
-
- writer.Close();
- }
-
- public void Serialize( XmlWriter writer, object graph )
- {
- Serialize( writer, graph, null, true, false, true );
- }
-
- public void Serialize( XmlWriter writer, object graph,
- Type rootType, bool preserveObjectReferences,
- bool writeContentOnly,
- bool ignoreUnknownSerializationData )
- {
- Type t = graph.GetType();
-
- //writer.WriteStartDocument();
-
- if( Type.GetTypeCode( t ) == TypeCode.Object )
- {
- writer.WriteStartElement( "root" );
-
- Assembly assem = t.Assembly;
-
- string assemName = assem.GetName().Name;
-
- writer.WriteAttributeString( "t", graph.GetType().FullName + ", " + assemName );
-
- FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly );
-
- foreach( FieldInfo fi in fiArr )
- {
- Serialize( writer, fi.Name, fi.GetValue( graph ) );
-
- /*
- if( fi.FieldType.IsClass )
- {
- Serialize( writer, fi.GetValue( graph ), rootType, preserveObjectReferences, writeContentOnly, ignoreUnknownSerializationData );
- }
- else
- {
- SerializePod( writer, fi.GetValue( graph ) );
- }
- */
- }
-
- writer.WriteEndElement();
- }
-
- //writer.WriteEndDocument();
- }
-
- private ObjectIDGenerator m_idGenerator = new ObjectIDGenerator();
- private Dictionary m_alreadyDeserialzied = new Dictionary();
-
- public void Serialize( XmlWriter writer, string name, object obj )
- {
- writer.WriteStartElement( name );
-
- if( obj != null )
- {
- Type t = obj.GetType();
-
- if( Type.GetTypeCode( t ) == TypeCode.Object )
- {
- bool first = false;
- if( !m_alreadyDeserialzied.ContainsKey( m_idGenerator.GetId( obj, out first ) ) )
- {
- m_alreadyDeserialzied[m_idGenerator.GetId( obj, out first )] = obj;
-
- Assembly assem = t.Assembly;
-
- string assemName = assem.GetName().Name;
-
- if( !t.IsArray )
- {
- writer.WriteAttributeString( "t", t.FullName + ", " + assemName );
-
- writer.WriteAttributeString( "ref", m_idGenerator.GetId( obj, out first ).ToString() );
-
- FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public );
-
- foreach( FieldInfo fi in fiArr )
- {
- Serialize( writer, fi.Name, fi.GetValue( obj ) );
- }
- }
- else
- {
- Array arr = (Array)obj;
-
- Type aType = t.GetElementType();
-
- string aTypeString = aType.FullName;
-
- writer.WriteAttributeString( "t", aTypeString + ", " + assemName );
-
- writer.WriteAttributeString( "c", arr.Length.ToString() );
-
- for( int i = 0; i < arr.Length; ++i )
- {
- Serialize( writer, "val", arr.GetValue( i ) );
- }
-
- //writer.WriteStartElement( "values" );
-
-
-
- //writer.WriteEndElement();
-
- }
- }
- else
- {
- writer.WriteAttributeString( "ref", m_idGenerator.GetId( obj, out first ).ToString() );
- }
- }
- else
- {
- writer.WriteAttributeString( "t", t.FullName );
-
- writer.WriteAttributeString( "v", obj.ToString() );
- }
- }
- else
- {
- writer.WriteAttributeString( "null", "" );
- }
-
- writer.WriteEndElement();
- }
-
- }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/*
-///
-///
-///
-public class XmlFormatter : IFormatter
-{
- public enum ETypes
- {
- Array,
- Int32,
- Ref,
- Object,
- EndObject,
- Single,
- Double,
- Char,
- String,
- Boolean,
- EndStream,
- }
-
-
- public XmlFormatter()
- {
- //
- // TODO: Add constructor logic here
- //
- }
-
-
- #region Useless
- public ISurrogateSelector SurrogateSelector
- {
- get
- {
- return null;
- }
-
- set
- {
- }
- }
-
- public SerializationBinder Binder
- {
- get
- {
- return null;
- }
-
- set
- {
- }
- }
-
- public StreamingContext Context
- {
- get
- {
- return new StreamingContext();
- }
-
- set
- {
- }
- }
- #endregion Useless
-
- Queue m_objectsToBeDeserialized = new Queue();
- Hashtable m_alreadyDeserialzied = new Hashtable();
- //int m_GUID = 0;
-
- #region Serialize
- public void Serialize( System.IO.Stream stream, object obj )
- {
- //Default is 4k
- //BufferedStream bufStream = new BufferedStream( stream );
-
- TextWriter writer = new StreamWriter( stream );
-
- writeObject( writer, obj );
-
- while( m_objectsToBeDeserialized.Count != 0 )
- {
- object objToDes = m_objectsToBeDeserialized.Dequeue();
-
- writeObject( writer, objToDes );
- }
-
- writer.Write( (char)ETypes.EndStream );
- }
-
- void writeRefAndSched( TextWriter writer, object obj )
- {
- //if( m_alreadyDeserialzied[ obj.GetType().GetArrayRank(
-
- if( obj == null )
- {
- writer.Write( 0 );
- return;
- }
-
-
- //Now write the address.
- //Bad bad. Need to do this correctly.
- int objRef = obj.GetHashCode();
- writer.Write( objRef );
-
- if( m_alreadyDeserialzied[ obj ] == null )
- {
- m_alreadyDeserialzied[ obj ] = obj;
- m_objectsToBeDeserialized.Enqueue( obj );
- }
- }
-
- void dispatchWrite( TextWriter writer, object parentObj, FieldInfo fi )
- {
- string typeName = fi.FieldType.Name;
-
- string name = fi.Name;
-
- if( fi.IsNotSerialized )
- {
- return;
- }
-
- if( fi.FieldType.IsArray )
- {
- writer.Write( (char)ETypes.Array );
- writer.Write( name.GetHashCode() );
-
- writeArray( writer, (Array)fi.GetValue( parentObj ) );
- }
- else if( ( fi.FieldType.IsClass || fi.FieldType.IsInterface ) && typeName != "String" )
- {
- writer.Write( (char)ETypes.Ref );
- writer.Write( name.GetHashCode() );
-
- writeRefAndSched( writer, fi.GetValue( parentObj ) );
- }
- else if( fi.FieldType.IsEnum )
- {
- writer.Write( (char)ETypes.Int32 );
- writer.Write( name.GetHashCode() );
-
- writer.Write( Convert.ToInt32( fi.GetValue( parentObj ) ) );
- }
- else
- {
- switch( typeName )
- {
- case "Int32":
- writer.Write( (char)ETypes.Int32 );
- writer.Write( name.GetHashCode() );
-
- writer.Write( Convert.ToInt32( fi.GetValue( parentObj ) ) );
- break;
- case "Single":
- writer.Write( (char)ETypes.Single );
- writer.Write( name.GetHashCode() );
-
- writer.Write( Convert.ToSingle( fi.GetValue( parentObj ) ) );
- break;
- case "Double":
- writer.Write( (char)ETypes.Double );
- writer.Write( name.GetHashCode() );
-
- writer.Write( Convert.ToDouble( fi.GetValue( parentObj ) ) );
- break;
- case "Char":
- writer.Write( (char)ETypes.Char );
- writer.Write( name.GetHashCode() );
-
- writer.Write( Convert.ToChar( fi.GetValue( parentObj ) ) );
- break;
- case "String":
- writer.Write( (char)ETypes.String );
- writer.Write( name.GetHashCode() );
-
- writer.Write( Convert.ToString( fi.GetValue( parentObj ) ) );
- break;
- case "Boolean":
- writer.Write( (char)ETypes.Boolean );
- writer.Write( name.GetHashCode() );
-
- writer.Write( Convert.ToBoolean( fi.GetValue( parentObj ) ) );
- break;
- default:
- Console.WriteLine( "VersionFormatter does not understand type " + typeName );
- break;
- }
- }
- }
-
- void writeArray( TextWriter writer, Array array )
- {
- if( array == null )
- {
- writer.Write( (int)-1 );
- return;
- }
-
- writer.Write( array.Length );
-
- foreach( object obj in array )
- {
- writeRefAndSched( writer, obj );
- }
- }
-
- void getAllFields( object obj, ArrayList list )
- {
- Type t = obj.GetType();
-
- while( t != null )
- {
- FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly );
- list.AddRange( fiArr );
-
- t = t.BaseType;
- }
- }
-
-
- void writeObject( TextWriter writer, object obj )
- {
- Type objType = obj.GetType();
-
- writer.Write( (char)ETypes.Object );
- writer.Write( objType.FullName );
-
- int objRef = obj.GetHashCode();
- writer.Write( objRef );
-
- ArrayList list = new ArrayList();
-
- getAllFields( obj, list );
-
- foreach( FieldInfo fi in list )
- {
- dispatchWrite( writer, obj, fi );
- }
-
- writer.Write( (char)ETypes.EndObject );
- }
-
- void write( TextWriter wr, TType val )
- {
- //wr.Write( val );
- }
-
- /*
- void writeInt( TextWriter writer, int val )
- {
- writer.Write( val );
- }
-
- void writeSingle( TextWriter writer, float val )
- {
- writer.Write( val );
- }
-
- void writeDouble( TextWriter writer, double val )
- {
- writer.Write( val );
- }
-
- void writeChar( TextWriter writer, char val )
- {
- writer.Write( val );
- }
-
- void writeString( TextWriter writer, string val )
- {
- writer.Write( val );
- }
-
- void writeBool( TextWriter writer, bool val )
- {
- writer.Write( val );
- }
- * /
- #endregion Serialize
-
-
- #region Deserialize
-
- class Fixup
- {
- public Fixup( int guid, object obj, FieldInfo fi )
- {
- m_guid= guid;
- m_obj = obj;
- m_fi = fi;
- }
-
- XmlFormatter
-
- public Fixup( int guid, object obj, int index )
- {
- m_guid = guid;
- m_obj = obj;
- m_index= index;
- }
-
- public readonly int m_guid = 0;
- public readonly object m_obj = null;
-
- public readonly FieldInfo m_fi = null;
- public readonly int m_index= -1;
-
- }
-
- Hashtable m_mapGUIDToObject = new Hashtable();
- ArrayList m_fixupList = new ArrayList();
-
- ArrayList m_desObjects = new ArrayList();
-
- public object Deserialize( System.IO.Stream stream )
- {
- StreamReader reader = new StreamReader( stream );
-
- object objRoot = null;
-
- //Read in the first object.
- {
- ETypes type = (ETypes)reader.ReadChar();
-
- Debug.Assert( type == ETypes.Object );
-
- objRoot = readObject( reader );
-
- m_desObjects.Add( objRoot );
- }
-
- bool readObjects = true;
-
- while( readObjects )
- {
- ETypes type = (ETypes)reader.ReadChar();
-
- Debug.Assert( type == ETypes.Object || type == ETypes.EndStream );
-
- if( type == ETypes.Object )
- {
- object obj = readObject( reader );
-
- m_desObjects.Add( obj );
- }
- else
- {
- Debug.Assert( type == ETypes.EndStream );
-
- readObjects = false;
- }
- }
-
- foreach( Fixup fu in m_fixupList )
- {
- //Fixup fix = m_fixups[
-
- object obj = m_mapGUIDToObject[ fu.m_guid ];
-
- if( obj != null )
- {
- if( fu.m_fi != null )
- {
- fu.m_fi.SetValue( fu.m_obj, obj );
- }
- else
- {
- Debug.Assert( fu.m_index >= 0 );
-
- object []array = (object [])fu.m_obj;
-
- array[ fu.m_index ] = obj;
- }
- }
- else
- {
- Console.WriteLine( "Obj to ref is null." );
- }
- }
-
- foreach( object obj in m_desObjects )
- {
- if( typeof( IDeserializationCallback ).IsAssignableFrom( obj.GetType() ) )
- {
- IDeserializationCallback desCB = (IDeserializationCallback)obj;
-
- if( desCB != null )
- {
- desCB.OnDeserialization( this );
- }
- }
- }
-
- return objRoot;
- }
-
-
-
- bool dispatchRead( StreamReader reader, object obj, Hashtable ht )
- {
-
- //Read the type
- ETypes type = (ETypes)reader.ReadChar();
-
- if( type == ETypes.EndObject )
- {
- return false;
- }
-
- int nameHash = reader.ReadInt32();
-
- FieldInfo fi = (FieldInfo)ht[ nameHash ];
-
- if( fi == null )
- {
- Console.WriteLine( "Field no longer exists" );
- }
-
- try
- {
- switch( type )
- {
- case ETypes.Array:
- readArray( reader, obj, fi );
- break;
- case ETypes.Int32:
- readInt( reader, obj, fi );
- break;
- case ETypes.Single:
- readSingle( reader, obj, fi );
- break;
- case ETypes.Double:
- readDouble( reader, obj, fi );
- break;
- case ETypes.Char:
- readChar( reader, obj, fi );
- break;
- case ETypes.Boolean:
- readBool( reader, obj, fi );
- break;
- case ETypes.String:
- readString( reader, obj, fi );
- break;
- case ETypes.Ref:
- readRef( reader, obj, fi );
- break;
- case ETypes.Object:
- readObject( reader );
- break;
- default:
- Debug.Fail( "Unknown type on read." );
- break;
- }
- }
- catch( Exception ex )
- {
- Console.WriteLine( "Exception: " + ex.Message );
- Console.WriteLine( "Stack: " + ex.StackTrace );
- }
-
-
- return true;
- }
-
- object createObject( string objTypeName )
- {
- Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
-
- foreach( Assembly a in ass )
- {
- Type t = a.GetType( objTypeName );
-
- if( t != null )
- {
- object obj = FormatterServices.GetUninitializedObject( t );
-
- if( obj != null )
- {
- return obj;
- }
- }
- }
-
- return null;
- }
-
-
- object readObject( StreamReader reader )
- {
- //ETypes type = (ETypes)reader.ReadChar();
-
- //Debug.Assert( type == ETypes.Object, "Expecting type Object" );
-
- string objTypeName = reader.ReadString();
- int objGUID = reader.ReadInt32();
-
- try
- {
- object obj = createObject( objTypeName );
-
- m_mapGUIDToObject[ objGUID ] = obj;
-
- ArrayList list = new ArrayList();
- Hashtable ht = new Hashtable();
-
- if( obj != null )
- {
- getAllFields( obj, list );
-
- foreach( FieldInfo fi in list )
- {
- ht[ fi.Name.GetHashCode() ] = fi;
- }
- }
-
- while( dispatchRead( reader, obj, ht ) )
- {
- }
-
- return obj;
- }
- catch( Exception ex )
- {
- Console.WriteLine( "Exception: " + ex.Message );
- }
-
- return null;
- }
-
- void readArray( StreamReader reader, object obj, FieldInfo fi )
- {
- int length = reader.ReadInt32();
-
- if( length < 0 )
- {
- if( fi == null ) return;
-
- fi.SetValue( obj, null );
-
- return;
- }
-
- object[] array = new object[length];
-
- if( fi != null )
- {
- fi.SetValue( obj, array );
- }
-
- for( int i=0; i te.PayloadStringByName( name ) ?? def;
-
- public static T Get( this TraceEvent te, string name, T def = default )
- {
- var index = te.PayloadIndex( name );
-
- if( index <= 0 )
- return default;
-
- var value = te.PayloadValue( index );
-
-
- if( value.GetType() != typeof( T ) )
- {
- log.warn( $"In {te.ID} Payload {name} is type {value.GetType().FriendlyName()} not {typeof( T ).FriendlyName()}" );
- return default;
- }
-
- return (T)value;
- }
-
-
-}
-
-
-public class LogGC
-{
- static ImmutableHashSet blacklist;
- static ImmutableHashSet stacklist;
-
- static LogGC()
- {
- blacklist = ImmutableHashSet.Create(
- "FAKE_TEST",
- "GC/BulkMovedObjectRanges",
-
- /*
- "GC/BulkSurvivingObjectRanges",
- "GC/BulkRootStaticVar",
- "GC/BulkNode",
- "GC/BulkEdge",
- "GC/BulkRootEdge",
- "GC/FinalizeObject",
- "GC/SetGCHandle",
- "GC/DestoryGCHandle",
- "GC/MarkWithType",
- "GC/SuspendEEStart",
- "GC/SuspendEEStop",
-
- "GC/RestartEEStart",
- "GC/RestartEEStop",
-
- "GC/FinalizersStart",
- // "GC/FinalizersStop", //Keep this one since it has details
-
- "GC/GenerationRange",
- "GC/FitBucketInfo",
-
- "TieredCompilation/BackgroundJitStart",
-
- "Type/BulkType",
- "TypeLoad/Start",
-
- "Method/R2RGetEntryPointStart",
- "Method/MethodDetails",
- "Method/MemoryAllocatedForJitCode",
- "Method/JittingStarted",
- "Method/ILToNativeMap",
-
- "ThreadPoolWorkerThread/Wait",
-
- "ILStub/StubGenerated"
- */
- "FAKE_END_IS_NOTHING"
-
- );
- stacklist = ImmutableHashSet.Create( "{TEST_ITEM}" );
-
- log.endpointForCat( "Method/MemoryAllocatedForJitCode", log.Endpoints.File );
- log.endpointForCat( "TypeLoad/Stop", log.Endpoints.File );
- log.endpointForCat( "GC/BulkRootStaticVar", log.Endpoints.File );
- log.endpointForCat( "GC/BulkNode", log.Endpoints.File );
- log.endpointForCat( "GC/BulkRootStaticVar", log.Endpoints.File );
-
- }
-
- static public void RegisterObjectId( object obj )
- {
- /*
- var gchWeak = GCHandle.Alloc( obj, GCHandleType.Weak );
- var gchNRML = GCHandle.Alloc( obj, GCHandleType.Normal );
-
- var intPtrWeak = GCHandle.ToIntPtr( gchWeak );
- var intPtrNRML = GCHandle.ToIntPtr( gchNRML );
-
- //var intPtr = Marshal.GetIUnknownForObject( obj );
- var intPtr = 0; //gchNRML.AddrOfPinnedObject();
-
- //Marshal.GetTypedObjectForIUnknown()
-
- // 0x00000003400111C0
- // 0000000000000000
-
- log.info( $"Log ObjectIDs: 0x{intPtrNRML.ToString("X"):0000000000000000} 0x{intPtrWeak.ToString("X"):0000000000000000}" );
- //*/
- }
-
-
- public static Action LogCategoryFunc( string catIn )
- {
- return ( TraceEvent te ) =>
- {
- var cat = catIn;
-
- if( blacklist.Contains( te.EventName ) )
- return;
-
- {
- var methodBeingCompiledNamespace = te.Get( "MethodBeingCompiledNamespace" );
- if( ( methodBeingCompiledNamespace.StartsWith( "Microsoft" ) || methodBeingCompiledNamespace.StartsWith( "System" ) ) )
- return;
- }
-
- {
- var methodNamespace = te.PayloadStringByName( "MethodNamespace" ) ?? "";
- if( ( methodNamespace.StartsWith( "Microsoft" ) || methodNamespace.StartsWith( "System" ) ) )
- return;
- }
-
- {
- var ns = te.PayloadStringByName( "TypeName" ) ?? "";
- if( ( ns.StartsWith( "Microsoft" ) || ns.StartsWith( "System" ) ) )
- return;
- }
-
-
-
- {
- var ns = te.PayloadStringByName( "TypeLoad/Stop" ) ?? "";
- if( ns.StartsWith( "Godot" ) )
- return;
- }
-
- {
- var payloadIndex = te.PayloadIndex( "count" );
-
- if( payloadIndex > 0 )
- {
- var count = (int)te.PayloadValue( payloadIndex );
- if( count > 16 )
- return;
- }
- }
-
- //
- //
-
- //
-
- if( !te.EventName.StartsWith( "EventID" ) )
- {
- var logDetails = "";
- // Custom event displays
- if( te.EventName == "Method/LoadVerbose" )
- {
- var optTier = te.Get( "OptimizationTier" );
- var methodNamespace = te.Get( "MethodNamespace" );
-
- if( optTier == "MinOptJitted" )
- return;
- if( methodNamespace.StartsWith( "FastSerialization" ) )
- return;
-
- log.info( $"{optTier} {LogGCExt.MethodInfo( te )}", cat: te.EventName );
-
- return;
- //logDetails = "| Details: ";
- }
- else if( te.EventName.StartsWith( "Method/Inlining" ) )
- {
- var methodNamespace = te.Get( "MethodBeingCompiledNamespace" );
-
- if( methodNamespace.StartsWith( "FastSerialization" ) )
- return;
-
- log.info( $"Inlining {te.Get( "FailReason" )} {te.Get( "OptimizationTier" )} {LogGCExt.MethodInfo( te, "MethodBeingCompiled" )}", cat: te.EventName );
-
- return;
- //logDetails = "| Details: ";
- }
- else if( te.EventName == "Type/BulkType" )
- {
- var val = te.ToString();
-
- XmlDocument doc = new();
-
- var stream = new MemoryStream();
- var writer = new StreamWriter( stream );
- writer.Write( val );
- writer.Flush();
- stream.Position = 0;
-
- doc.Load( stream );
-
- var root = doc.DocumentElement;
-
- XmlNodeList children = root.ChildNodes;
-
- foreach( var child in children )
- {
- var node = child as XmlElement;
- log.info( $"Child: {node.Name}" );
- }
-
- return;
- }
- else if( te.EventName == "TypeLoad/Stop" )
- {
- /*
- var typeName = te.PayloadStringByName( "TypeName" );
- if( typeName.StartsWith( "Godot." ) )
- return;
-
- log.info( $"{typeName} Level: {te.PayloadStringByName( "LoadLevel" )}", cat: te.EventName );
- //*/
-
- return;
-
- //logDetails = "| Details: ";
- }
- else if( te.EventName.StartsWith( "Method/R2RGetEntryPoint" ) )
- {
- log.info( $"{LogGCExt.MethodInfo( te )} Entry: {te.PayloadStringByName( "EntryPoint" )}", cat: te.EventName );
- return;
- //logDetails = "| Details: ";
- }
- else if( te.EventName.StartsWith( "Contention/LockCreated" ) )
- {
- // "Contention/Start" AssociatedObjectID
- // System.Runtime.InteropServices.GCHandle.FromIntPtr(
-
- var lockId = te.Get( "LockID" );
- var objId = te.Get( "AssociatedObjectID" );
-
- var testObj = Marshal.GetIUnknownForObject( objId );
-
- var intPtrStr = te.PayloadStringByName( "AssociatedObjectID" ).Substring( 2 );
-
- try
- {
- //var intPtr = Convert.ToUInt64( intPtrStr, 16 );
-
- //var gch = System.Runtime.InteropServices.GCHandle.FromIntPtr( intPtr );
- var gch = new GCHandle();
-
-
- //*
- var allocated = gch.IsAllocated;
- var obj = gch.Target;
-
- log.info( $"Lock {lockId} Create {objId.ToString( "X" )} {obj?.GetType()?.Name} {obj}", cat: te.EventName );
- //*/
- }
- catch( Exception ex )
- {
- log.info( $"Lock {lockId} Create 0x{intPtrStr} (Could not get object) [{ex.Message}]", cat: te.EventName );
- }
-
- LogGeneric( te, "| Raw: " );
-
- return;
- //logDetails = "| Details: ";
- }
- else if( te.EventName.StartsWith( "Contention/Start" ) )
- {
- // EventName="Contention/Start" ContentionFlags="Managed" LockID="0x000000011D015CB8" AssociatedObjectID="0x00000003504554C0" LockOwnerThreadID="0"
- // EventName="Contention/Stop" ContentionFlags="Managed" DurationNs="26000"
-
- var lockId = te.Get( "LockID" );
- var objId = te.Get( "AssociatedObjectID" );
- var threadId = te.Get( "LockOwnerThreadID" );
-
- log.info( $"Lock {lockId} {te.Get( "ContentionFlags" )} in thread {threadId} on obj 0x{objId.ToString( "X" )} ", cat: te.EventName );
-
- LogGeneric( te, "| Raw: " );
- }
- else if( te.EventName.StartsWith( "Contention/Stop" ) )
- {
- //var lockId = te.Get( "LockID" );
- //var objId = te.Get( "AssociatedObjectID" );
- //var threadId = te.Get( "LockOwnerThreadID" );
-
- log.info( $"Lock {{lockId}} {te.Get( "ContentionFlags" )} Duration {te.Get( "DurationNs" )}ns", cat: te.EventName );
-
- LogGeneric( te, "| Raw: " );
- }
- else if( te.EventName.StartsWith( "AssemblyLoader/" ) || te.EventName.StartsWith( "Loader/" ) )
- {
- //AssemblyLoader/Start AssemblyName AssemblyLoadContext RequestingAssemblyLoadContext AssemblyPath RequestingAssembly
- //AssemblyLoader/Stop AssemblyName AssemblyLoadContext RequestingAssemblyLoadContext AssemblyPath RequestingAssembly Success ResultAssemblyName ResultAssemblyPath Cached
- //Loader/AssemblyLoad AssemblyID AppDomainID AssemblyFlags FullyQualifiedAssemblyName BindingID
- //AssemblyLoader/ResolutionAttempted
- // AssemblyName AssemblyLoadContext Result ResultAssemblyName ResultAssemblyPath Stage ErrorMessage
-
- //Loader/ModuleLoad ModuleID AssemblyID ModuleFlags ModuleILPath ModuleNativePath ManagedPdbSignature ManagedPdbAge ManagedPdbBuildPath
- //Loader/DomainModuleLoad ModuleID AssemblyID ModuleFlags ModuleILPath ModuleNativePath AppDomainID
-
- //AssemblyLoader/KnownPathProbed FilePath Source Result
- var appDomainId = te.Get( "AppDomainID" );
-
- var asId = te.Get( "AssemblyID" );
- var asName = te.Get( "AssemblyName" );
- var asPath = te.Get( "AssemblyPath" );
- var asLC = te.Get( "AssemblyLoadContext" );
-
- var reqAs = te.Get( "RequestingAssembly" );
- var reqAsLC = te.Get( "RequestingAssemblyLoadContext" );
-
- var reqAsName = te.Get( "ResultAssemblyName" );
- var reqAsPath = te.Get( "ResultAssemblyPath" );
-
- var success = te.Get( "Success" );
- var cached = te.Get( "Cached" );
- var errMsg = te.Get( "ErrorMessage" );
- var stage = te.Get( "Stage" );
- var result = te.Get( "Result" );
- var source = te.Get( "Source" );
-
- var modId = te.Get( "ModuleID" );
- var modFlags = te.Get( "ModuleFlags" );
- var modILPath = te.Get( "ModuleILPath" );
- var modNativePath = te.Get( "ModuleNativePath" );
-
- var manBuildPath = te.Get( "ManagedPdbBuildPath" );
- var fqaName = te.Get( "FullyQualifiedAssemblyName" );
- var bindingId = te.Get( "BindingID" );
-
- }
-
-
-
-
-
- //76 CHARACTERS
- // 0 )
- {
- Encoding enc = new UnicodeEncoding(false, false, true);
- var eventDataUtf16 = enc.GetString( eventData );
- log.debug( $"> {eventDataUtf16}" );
- }
- */
- }
- else
- {
- /*
- var payloadNames = te.PayloadNames;
- var channel = te.Channel;
- var formattedMsg = te.FormattedMessage;
- var keywords = te.Keywords;
- var source = te.Source;
- var dump = te.Dump();
- var dynMemberNames = te.GetDynamicMemberNames();
- var dataStart = te.DataStart;
- */
-
- var eventData = te.EventData();
-
- //var eventDataStr = eventData.ToString();
-
- Encoding enc = new UnicodeEncoding( false, false, true );
- var eventDataUtf16 = enc.GetString( eventData );
- //var safeEventData = eventDataUtf16.Replace( (char)0, '\n' );
-
- var arrEventData = eventDataUtf16.Split( (char)0 );
- var joinedEventData = string.Join( " | ", arrEventData );
-
- //log.info( $"{te.FormattedMessage}", cat: catIn );
- log.info( $"{joinedEventData}", cat: catIn );
- }
-
-
- };
- }
-
- private static ConcurrentDictionary> s_validKeywords = new();
-
- private static void LogGeneric( TraceEvent te, string logDetails )
- {
- var teStr = te.ToString().Replace( "ClrInstanceID=\"0\"", "" );
-
- /*
-
- */
-
- var startIndex = teStr.IndexOf( "EventName" );
-
- //log.debug( $"{logDetails} {startIndex} {teStr}", cat: te.EventName );
-
- var teStrSlice = teStr.AsSpan( startIndex, teStr.Length - ( startIndex + 1 + 1 ) );
-
- log.debug( $"{logDetails}{teStrSlice}", cat: te.EventName );
-
- /*
- try
- {
- TraceCallStack? callstack = te.CallStack();
- //if( callstack != null) log.trace( $"| Callstack: {callstack?.ToString()}" );
- if( callstack != null )
- {
- log.trace( $"| Callstack:" );
- log.trace( $"| {callstack.Depth}" );
- log.trace( $"| {callstack.CodeAddress}" );
- }
- }
- catch( Exception ex )
- {
- log.debug( $"Caught {ex.Message} while getting the callstack" );
- }
- //*/
- }
-
- public static void PrintRuntimeGCEvents( int processId )
- {
- var providers = new List()
- {
- new EventPipeProvider("Microsoft-Windows-DotNETRuntime",
- EventLevel.Verbose, (long)(
- TraceKeywords.GC |
- TraceKeywords.Contention |
- TraceKeywords.Debugger |
- TraceKeywords.Exception |
- TraceKeywords.GCAllObjectAllocation |
- TraceKeywords.GCSampledObjectAllocationHigh |
- TraceKeywords.GCSampledObjectAllocationLow |
- TraceKeywords.Security |
- TraceKeywords.Threading |
- TraceKeywords.Type |
- TraceKeywords.TypeDiagnostic |
- TraceKeywords.WaitHandle |
- TraceKeywords.All
- ) )
- };
-
- var client = new DiagnosticsClient( processId );
- using( EventPipeSession session = client.StartEventPipeSession( providers, false ) )
- {
- var source = new EventPipeEventSource( session.EventStream );
-
-
- source.Clr.GCAllocationTick += OnAllocTick;
-
- //source.Clr.All += LogCategoryFunc( "clr" );
-
- //source.Kernel.All += LogCategoryFunc( "kernel" );
-
- // Doesnt seem to be too interesting.
- //source.Dynamic.All += LogCategoryFunc( "dynamic" );
-
-
- try
- {
- source.Process();
- }
- catch( Exception e )
- {
- Console.WriteLine( "Error encountered while processing events" );
- Console.WriteLine( e.ToString() );
- }
- }
- }
-
- private static void OnAllocTick( GCAllocationTickTraceData data )
- {
- }
-}
-
diff --git a/logging/Tracing.cs b/logging/Tracing.cs
deleted file mode 100644
index 8b797b7..0000000
--- a/logging/Tracing.cs
+++ /dev/null
@@ -1,675 +0,0 @@
-using Microsoft.Diagnostics.Symbols;
-using Microsoft.Diagnostics.Tracing;
-using Microsoft.Diagnostics.Tracing.Etlx;
-using Microsoft.Diagnostics.Tracing.Parsers;
-using Microsoft.Diagnostics.Tracing.Parsers.Clr;
-using Microsoft.Diagnostics.Tracing.Parsers.Kernel;
-using Microsoft.Diagnostics.Tracing.Session;
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Diagnostics.NETCore.Client;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Diagnostics.Tracing;
-
-namespace Tracing
-{
- ///
- /// A configurable, real-time EventPipe trace monitor for cross-platform use.
- /// This class uses a fluent builder pattern to attach to a .NET process,
- /// configure EventPipe providers, and process events in real-time.
- ///
- public class EventPipeTraceMonitor : IDisposable
- {
- private readonly int _pid;
- private int _durationSec = 10;
- private ClrTraceEventParser.Keywords _clrKeywords = ClrTraceEventParser.Keywords.None;
- private bool _monitorCpu = false;
- private readonly List _customProviders = new();
-
- private Action _userCallback;
- private EventPipeSession _session;
- private TraceEventSource _traceLogSource; /// CHANGED
- private Task _processingTask;
-
-
- private Timer _timer;
-
- public EventPipeTraceMonitor( int processId )
- {
- _pid = processId;
- }
-
- // ####################################################################
- // Builder Configuration Methods
- // ####################################################################
-
- public EventPipeTraceMonitor WithDuration( int seconds )
- {
- _durationSec = seconds;
- return this;
- }
-
- ///
- /// Adds a custom EventPipeProvider.
- ///
- public EventPipeTraceMonitor AddProvider( EventPipeProvider provider )
- {
- _customProviders.Add( provider );
- return this;
- }
-
- // ####################################################################
- // Event Selection Methods
- // ####################################################################
-
- public EventPipeTraceMonitor MonitorExceptions()
- {
- // EventPipe requires JIT/Loader/Stack keywords to resolve symbols
- _clrKeywords |= ClrTraceEventParser.Keywords.Exception |
- ClrTraceEventParser.Keywords.Stack |
- ClrTraceEventParser.Keywords.Jit |
- ClrTraceEventParser.Keywords.JittedMethodILToNativeMap |
- ClrTraceEventParser.Keywords.Loader;
- return this;
- }
-
- public EventPipeTraceMonitor MonitorModuleLoads()
- {
- _clrKeywords |= ClrTraceEventParser.Keywords.Loader |
- ClrTraceEventParser.Keywords.Stack |
- ClrTraceEventParser.Keywords.Jit |
- ClrTraceEventParser.Keywords.Threading |
- ClrTraceEventParser.Keywords.PerfTrack |
- ClrTraceEventParser.Keywords.JittedMethodILToNativeMap;
- return this;
- }
-
- public EventPipeTraceMonitor MonitorCpuSamples()
- {
- _monitorCpu = true;
- return this;
- }
-
- // ####################################################################
- // Core Execution Methods
- // ####################################################################
-
- public void Start( Action onEventCallback )
- {
- _userCallback = onEventCallback;
- var providers = new List( _customProviders );
-
-
-
-
-
- if( _clrKeywords != ClrTraceEventParser.Keywords.None )
- {
- // Add the main CLR provider
- providers.Add( new EventPipeProvider(
- "Microsoft-Windows-DotNETRuntime",
- EventLevel.Informational,
- (long)_clrKeywords ) );
- }
-
- if( _monitorCpu )
- {
- // Add the CPU sampler provider
- providers.Add( new EventPipeProvider(
- "Microsoft-DotNETCore-SampleProfiler",
- EventLevel.Informational ) );
- }
-
-
-
-
-
-
- if( !providers.Any() )
- {
- log.warn( "No trace providers configured. Monitor will not start." );
- return;
- }
-
- try
- {
- var client = new DiagnosticsClient( _pid );
- log.info( $"Starting EventPipe session on PID {_pid} for {_durationSec}s..." );
-
- // Start the session. requestRundown=true is critical
- // to get symbols for code JIT-compiled before the session started.
- _session = client.StartEventPipeSession( providers, requestRundown: true );
-
- // Set up the timer to stop the session
- _timer = new Timer( delegate
- {
- log.info( $"Monitoring duration ({_durationSec} sec) elapsed." );
- Stop();
- }, null, _durationSec * 1000, Timeout.Infinite );
-
- // Create the TraceLogSource from the session's event stream
- _traceLogSource = new EventPipeEventSource( _session.EventStream );
- // KEEP TraceLog.CreateFromTraceEventSession( _session );
-
- // Register callbacks based on requested keywords
- if( ( _clrKeywords & ClrTraceEventParser.Keywords.Exception ) != 0 )
- _traceLogSource.Clr.ExceptionStart += OnEvent;
- if( ( _clrKeywords & ClrTraceEventParser.Keywords.Loader ) != 0 )
- {
- _traceLogSource.Clr.LoaderModuleLoad += OnEvent;
- _traceLogSource.Clr.All += OnAllEvents;
-
- }
- //if( _monitorCpu )
- // _traceLogSource.CpuSpeedMHz += OnEvent;
-
- // Start processing the stream on a background thread.
- // .Process() is a blocking call that runs until the stream ends.
- _processingTask = Task.Run( () =>
- {
- try
- {/* _traceLogSource.Pro;*/ }
- catch( Exception ex ) { log.error( $"Trace processing error: {ex.Message}" ); }
- log.info( "Event processing finished." );
- } );
- }
- catch( Exception ex )
- {
- log.error( $"Failed to start EventPipe session: {ex.Message}" );
- }
-
-
-
-
- }
-
- private void OnAllEvents( TraceEvent evt )
- {
- log.info( $"EVENT: [PID:{evt.ProcessID}] -- {evt.EventName}" );
- }
-
- public void Stop()
- {
- if( _session != null )
- {
- log.info( "Stopping session..." );
- _timer?.Dispose();
- _timer = null;
-
- // Stopping the session will end the stream,
- // which causes traceLogSource.Process() to return.
- _session.Stop();
- _session.Dispose();
- _session = null;
-
- _traceLogSource?.Dispose();
- _traceLogSource = null;
-
- // Wait for the processing task to complete
- _processingTask?.Wait( 2000 );
- _processingTask = null;
- }
- }
-
- public void Dispose()
- {
- Stop();
- }
-
- ///
- /// Internal event handler.
- ///
- private void OnEvent( TraceEvent data )
- {
- // --- Pre-filtering ---
- if( data.Opcode == TraceEventOpcode.DataCollectionStart )
- return;
- if( data is ExceptionTraceData exd && exd.ExceptionType.Length == 0 )
- return;
-
- // --- Pass to user ---
- _userCallback( data );
- }
- }
-
- ///
- /// A configurable, real-time ETW trace monitor. (Windows-Only)
- /// This class uses a fluent builder pattern to configure and run a real-time
- /// TraceEventSession, processing events through a user-provided callback.
- ///
- public class RealTimeTraceMonitor : IDisposable
- {
- private TraceEventSession _session;
- private int _durationSec = 10;
- private string _processFilter = null;
- private KernelTraceEventParser.Keywords _kernelKeywords = KernelTraceEventParser.Keywords.ImageLoad | KernelTraceEventParser.Keywords.Process;
- private ClrTraceEventParser.Keywords _clrKeywords = ClrTraceEventParser.Keywords.None;
- private KernelTraceEventParser.Keywords _kernelStackKeywords = KernelTraceEventParser.Keywords.None;
- private bool _enableRundown = false;
- private bool _resolveNativeSymbols = false;
- private readonly List> _eventRegistrars = new();
- private Action _userCallback;
- private SymbolReader _symbolReader;
- private readonly object _symbolReaderLock = new();
- private TextWriter _symbolLog = new StringWriter();
- private Timer _timer;
-
- // ####################################################################
- // Builder Configuration Methods
- // ####################################################################
-
- ///
- /// Sets the monitoring duration in seconds.
- ///
- public RealTimeTraceMonitor WithDuration( int seconds )
- {
- _durationSec = seconds;
- return this;
- }
-
- ///
- /// Filters events to only include those from a process whose name contains this string.
- ///
- public RealTimeTraceMonitor FilterByProcess( string processName )
- {
- _processFilter = processName;
- return this;
- }
-
- ///
- /// Provides a TextWriter for detailed symbol lookup messages.
- ///
- public RealTimeTraceMonitor WithSymbolLog( TextWriter logWriter )
- {
- _symbolLog = logWriter;
- return this;
- }
-
- // ####################################################################
- // Event Selection Methods
- // ####################################################################
-
- ///
- /// Enables monitoring for CLR Exceptions (ExceptionStart).
- /// Automatically enables JIT, Loader, and Stack keywords required for symbol resolution.
- ///
- public RealTimeTraceMonitor MonitorExceptions()
- {
- _clrKeywords |= ClrTraceEventParser.Keywords.Exception |
- ClrTraceEventParser.Keywords.Stack |
- ClrTraceEventParser.Keywords.Jit |
- ClrTraceEventParser.Keywords.JittedMethodILToNativeMap |
- ClrTraceEventParser.Keywords.Loader;
- _enableRundown = true;
- _resolveNativeSymbols = true; // Native symbol resolution is often needed for full exception stacks
- _eventRegistrars.Add( source => source.Clr.ExceptionStart += OnEvent );
- return this;
- }
-
- ///
- /// Enables monitoring for CLR Module Loads (LoaderModuleLoad).
- /// Automatically enables JIT, Loader, and Stack keywords.
- ///
- public RealTimeTraceMonitor MonitorModuleLoads()
- {
- _clrKeywords |= ClrTraceEventParser.Keywords.Loader |
- ClrTraceEventParser.Keywords.Stack |
- ClrTraceEventParser.Keywords.Jit |
- ClrTraceEventParser.Keywords.JittedMethodILToNativeMap;
- _enableRundown = true;
- _eventRegistrars.Add( source => source.Clr.LoaderModuleLoad += OnEvent );
- return this;
- }
-
- ///
- /// Enables monitoring for CPU Samples (PerfInfoSample).
- ///
- public RealTimeTraceMonitor MonitorCpuSamples()
- {
- _kernelKeywords |= KernelTraceEventParser.Keywords.Profile;
- _kernelStackKeywords |= KernelTraceEventParser.Keywords.Profile;
- _resolveNativeSymbols = true; // CPU samples require native symbol resolution
- _eventRegistrars.Add( source => source.Kernel.PerfInfoSample += OnEvent );
- return this;
- }
-
- ///
- /// Enables monitoring for arbitrary Kernel events.
- ///
- /// Kernel keywords to enable.
- /// Keywords to collect stacks for.
- public RealTimeTraceMonitor MonitorKernelEvents( KernelTraceEventParser.Keywords events, KernelTraceEventParser.Keywords stackEvents = KernelTraceEventParser.Keywords.None )
- {
- _kernelKeywords |= events;
- _kernelStackKeywords |= stackEvents;
- if( stackEvents != KernelTraceEventParser.Keywords.None )
- {
- _resolveNativeSymbols = true;
- }
- return this;
- }
-
- ///
- /// Enables monitoring for arbitrary CLR events.
- /// Note: For complex events, prefer the specific Monitor* methods.
- ///
- /// CLR keywords to enable.
- public RealTimeTraceMonitor MonitorClrEvents( ClrTraceEventParser.Keywords events )
- {
- _clrKeywords |= events;
- if( ( events & ClrTraceEventParser.Keywords.Stack ) != 0 )
- {
- _clrKeywords |= ClrTraceEventParser.Keywords.Jit |
- ClrTraceEventParser.Keywords.JittedMethodILToNativeMap |
- ClrTraceEventParser.Keywords.Loader;
- _enableRundown = true;
- _resolveNativeSymbols = true;
- }
- return this;
- }
-
- // ####################################################################
- // Core Execution Methods
- // ####################################################################
-
- ///
- /// Starts the monitoring session and blocks until the duration expires or Ctrl+C is pressed.
- ///
- /// The callback to execute for each filtered event.
- public void Start( Action onEventCallback )
- {
- if( !OperatingSystem.IsWindows() )
- {
- log.error( $"{nameof( RealTimeTraceMonitor )} is only supported on Windows (ETW)." );
- return;
- }
-
- _userCallback = onEventCallback;
- log.info( $"Starting {nameof( RealTimeTraceMonitor )} for {_durationSec} seconds." );
-
- if( TraceEventSession.GetActiveSessionNames().Contains( "TraceLogMonitorSession" ) )
- {
- log.warn( "Session 'TraceLogMonitorSession' is already active. Attaching." );
- }
-
- try
- {
- using( _session = new TraceEventSession( "TraceLogMonitorSession", TraceEventSessionOptions.Attach ) )
- {
- // Set up Ctrl-C to stop the session
- Console.CancelKeyPress += ( object sender, ConsoleCancelEventArgs cancelArgs ) =>
- {
- cancelArgs.Cancel = true;
- Stop();
- };
-
- SetupProviders();
- SetupSymbolReader();
-
- using( var traceLogSource = TraceLog.CreateFromTraceEventSession( _session ) )
- {
- // Register all requested event callbacks
- foreach( var registrar in _eventRegistrars )
- {
- registrar( traceLogSource );
- }
-
- // Set up a timer to stop processing after the duration
- _timer = new Timer( delegate ( object state )
- {
- log.info( $"Monitoring duration ({_durationSec} sec) elapsed." );
- Stop();
- }, null, _durationSec * 1000, Timeout.Infinite );
-
- log.info( "Processing events..." );
- traceLogSource.Process();
- log.info( "Event processing finished." );
- }
- }
- }
- catch( Exception ex )
- {
- log.error( $"Failed to start trace session: {ex.Message}" );
- log.error( "This often requires Admin privileges." );
- }
- finally
- {
- _session = null;
- }
- }
-
- ///
- /// Stops the monitoring session.
- ///
- public void Stop()
- {
- if( _session != null )
- {
- log.info( "Stopping session..." );
- _session.Dispose();
- _session = null;
- }
- if( _timer != null )
- {
- _timer.Dispose();
- _timer = null;
- }
- }
-
- public void Dispose()
- {
- Stop();
- }
-
- // ####################################################################
- // Private Helper Methods
- // ####################################################################
-
- private void SetupProviders()
- {
- log.info( $"Enabling Kernel Providers with keywords: {_kernelKeywords}" );
- try
- {
- _session.EnableKernelProvider( _kernelKeywords, _kernelStackKeywords );
- }
- catch( Exception ex )
- {
- log.error( $"Failed to enable Kernel provider: {ex}" );
- }
-
- if( _clrKeywords != ClrTraceEventParser.Keywords.None )
- {
- log.info( $"Enabling CLR Provider with keywords: {_clrKeywords}" );
- try
- {
- _session.EnableProvider(
- ClrTraceEventParser.ProviderGuid,
- TraceEventLevel.Informational,
- (ulong)_clrKeywords );
- }
- catch( Exception ex )
- {
- log.error( $"Failed to enable CLR provider: {ex}" );
- }
- }
-
- if( _enableRundown )
- {
- // Remove keywords not relevant for rundown
- var rundownKeywords = ( _clrKeywords & ~( ClrTraceEventParser.Keywords.Exception | ClrTraceEventParser.Keywords.Stack ) );
- rundownKeywords |= ClrTraceEventParser.Keywords.StartEnumeration;
-
- log.info( $"Enabling CLR Rundown Provider with keywords: {rundownKeywords}" );
- try
- {
- _session.EnableProvider(
- ClrRundownTraceEventParser.ProviderGuid,
- TraceEventLevel.Informational,
- (ulong)rundownKeywords );
- }
- catch( Exception ex )
- {
- log.error( $"Failed to enable CLR Rundown provider: {ex}" );
- }
- }
- }
-
- private void SetupSymbolReader()
- {
- if( _resolveNativeSymbols )
- {
- log.info( "Setting up SymbolReader for native symbol resolution." );
- var symbolPath = new SymbolPath( SymbolPath.SymbolPathFromEnvironment ).Add( SymbolPath.MicrosoftSymbolServerPath );
- _symbolReader = new SymbolReader( _symbolLog, symbolPath.ToString() );
- // Allow reading PDBs from "unsafe" locations (next to EXE)
- _symbolReader.SecurityCheck = ( path => true );
- }
- }
-
- ///
- /// Primary event handler.
- /// This method is called from multiple threads and must be thread-safe.
- ///
- private void OnEvent( TraceEvent data )
- {
- // --- Pre-filtering ---
- if( data.Opcode == TraceEventOpcode.DataCollectionStart )
- return;
- if( data is ExceptionTraceData exd && exd.ExceptionType.Length == 0 )
- return;
-
- // --- Process filter ---
- if( _processFilter != null && !data.ProcessName.Contains( _processFilter, StringComparison.OrdinalIgnoreCase ) )
- {
- return;
- }
-
- // --- Symbol Resolution ---
- var callStack = data.CallStack();
- if( callStack != null && _resolveNativeSymbols )
- {
- ResolveNativeStack( callStack );
- }
-
- // --- Pass to user ---
- _userCallback( data );
- }
-
- ///
- /// Resolves native symbols for a given call stack.
- /// This method locks the SymbolReader, as it is not thread-safe.
- ///
- private void ResolveNativeStack( TraceCallStack callStack )
- {
- if( _symbolReader == null )
- return;
-
- lock( _symbolReaderLock )
- {
- while( callStack != null )
- {
- var codeAddress = callStack.CodeAddress;
- if( codeAddress.Method == null )
- {
- var moduleFile = codeAddress.ModuleFile;
- if( moduleFile != null )
- {
- codeAddress.CodeAddresses.LookupSymbolsForModule( _symbolReader, moduleFile );
- }
- }
- callStack = callStack.Caller;
- }
- }
- }
- }
-
- ///
- /// Example implementation of the RealTimeTraceMonitor utility.
- ///
- internal class TraceLogMonitor
- {
- public static void Run()
- {
- log.info( "******************** RealTimeTraceLog DEMO ********************" );
-
- // Define a thread-safe callback to process events
- Action printCallback = ( TraceEvent data ) =>
- {
- // log.info is assumed to be thread-safe
- // Note: EventPipe data does not have ProcessName, as it's scoped to the process.
- log.info( $"EVENT: [PID:{data.ProcessID}] -- {data.EventName}" );
-
- var stack = data.CallStack();
- if( stack != null )
- {
- log.info( $"CALLSTACK: {stack}" );
- }
- };
-
- // Run an exception generator in the background
- Task.Factory.StartNew( delegate
- {
- Thread.Sleep( 3000 );
- ThrowException();
- } );
-
- try
- {
- if( OperatingSystem.IsWindows() )
- {
- log.info( "Windows detected. Using ETW-based RealTimeTraceMonitor." );
- using( var monitor = new RealTimeTraceMonitor() )
- {
- monitor.WithDuration( 10 )
- .MonitorExceptions()
- .MonitorModuleLoads()
- .Start( printCallback );
- }
- }
- else
- {
- log.info( "Non-Windows detected. Using EventPipe-based EventPipeTraceMonitor." );
- int currentPid = Process.GetCurrentProcess().Id;
- using( var monitor = new EventPipeTraceMonitor( currentPid ) )
- {
- monitor.WithDuration( 10 )
- .MonitorExceptions()
- .MonitorModuleLoads()
- //.MonitorCpuSamples() // Note: EventPipe CPU sampling is very noisy
- .Start( printCallback );
- }
- }
- }
- catch( Exception ex )
- {
- log.error( $"Monitoring failed: {ex}" );
- }
-
- log.info( "Finished monitoring." );
- }
-
- // --- Exception generation helpers ---
-
- [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.NoInlining )]
- private static void ThrowException()
- {
- ThrowException1();
- }
-
- [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.NoInlining )]
- private static void ThrowException1()
- {
- log.info( "Causing an exception to happen so a CLR Exception Start event will be generated." );
- try
- {
- throw new Exception( "This is a test exception thrown to generate a CLR event" );
- }
- catch( Exception ) { }
- }
- }
-}
diff --git a/mod/Modules.cs b/mod/Modules.cs
deleted file mode 100644
index af96caa..0000000
--- a/mod/Modules.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-//using System.Threading.Tasks;
-using System.Diagnostics;
-using System.Reflection;
-
-namespace mod
-{
-
- [Serializable]
- public class Config : lib.Config
- {
- public String name = "Generic";
- }
-
- public class View
- {
- }
-
- public class Base
- {
- public Config Cfg { get { return m_cfg; } }
-
- public Base( Config cfg )
- {
- m_cfg = cfg;
- }
-
- private Config m_cfg;
- }
-
-
- [Serializable]
- public class FluidConfig : Config
- {
- public String type = "none";
- }
-
-
- public class FluidBase : Base
- {
- public new FluidConfig Cfg { get { return (FluidConfig)base.Cfg; } }
-
- public FluidBase( FluidConfig cfg )
- : base( cfg )
- {
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- [Serializable]
- public class SystemConfig : Config
- {
- public String type = "none";
- }
-
-
- public class System
- {
- public SystemConfig Cfg { get { return m_cfg; } }
-
- public System( SystemConfig cfg )
- {
- m_cfg = cfg;
- }
-
- private SystemConfig m_cfg;
- }
-
-
-}
diff --git a/net/Conn.cs b/net/Conn.cs
deleted file mode 100644
index 31d3637..0000000
--- a/net/Conn.cs
+++ /dev/null
@@ -1,198 +0,0 @@
-
-#nullable enable
-
-using System;
-using System.Runtime.Serialization;
-using System.Net.Sockets;
-using System.IO;
-using System.Diagnostics.CodeAnalysis;
-
-//using Util;
-
-namespace lib
-{
-
- public interface IFormatter
- {
- //
- // Summary:
- // Gets or sets the System.Runtime.Serialization.SerializationBinder that performs
- // type lookups during deserialization.
- //
- // Returns:
- // The System.Runtime.Serialization.SerializationBinder that performs type lookups
- // during deserialization.
- SerializationBinder? Binder { get; set; }
- //
- // Summary:
- // Gets or sets the System.Runtime.Serialization.StreamingContext used for serialization
- // and deserialization.
- //
- // Returns:
- // The System.Runtime.Serialization.StreamingContext used for serialization and
- // deserialization.
- StreamingContext Context { get; set; }
- //
- // Summary:
- // Gets or sets the System.Runtime.Serialization.SurrogateSelector used by the current
- // formatter.
- //
- // Returns:
- // The System.Runtime.Serialization.SurrogateSelector used by this formatter.
- ISurrogateSelector? SurrogateSelector { get; set; }
-
- //
- // Summary:
- // Deserializes the data on the provided stream and reconstitutes the graph of objects.
- //
- //
- // Parameters:
- // serializationStream:
- // The stream that contains the data to deserialize.
- //
- // Returns:
- // The top object of the deserialized graph.
- [RequiresDynamicCode( "BinaryFormatter serialization uses dynamic code generation, the type of objects being processed cannot be statically discovered." )]
- [RequiresUnreferencedCode( "BinaryFormatter serialization is not trim compatible because the type of objects being processed cannot be statically discovered." )]
- object Deserialize( Stream serializationStream );
- //
- // Summary:
- // Serializes an object, or graph of objects with the given root to the provided
- // stream.
- //
- // Parameters:
- // serializationStream:
- // The stream where the formatter puts the serialized data. This stream can reference
- // a variety of backing stores (such as files, network, memory, and so on).
- //
- // graph:
- // The object, or root of the object graph, to serialize. All child objects of this
- // root object are automatically serialized.
- [RequiresUnreferencedCode( "BinaryFormatter serialization is not trim compatible because the type of objects being processed cannot be statically discovered." )]
- void Serialize( Stream serializationStream, object graph );
- }
-
-
- public interface IProcess
- {
- void process( object obj );
- }
-
-
- public interface ISerDes where T : IFormatter
- {
-
- T getInstance();
-
-
-
- }
-
-
- public class NewEveryCall : ISerDes where T : IFormatter, new()
- {
- public T getInstance()
- {
- return new T();
- }
- }
-
- public class Conn
- {
- public static int BufferSize = 2048;
- }
-
-
- public class Conn : Conn
- where T : IFormatter, new()
- where TInst : ISerDes, new()
- {
- public Socket Sock { get { return m_socket; } }
- public Stream Stream { get { return m_streamNet; } }
-
-
- private TInst m_formatter = new TInst();
-
-
- public Conn( Socket sock, IProcess proc )
- {
- m_socket = sock;
-
- sock.NoDelay = true;
-
- m_streamNet = new NetworkStream( m_socket );
-
- m_proc = proc;
- }
-
- public object receiveObject()
- {
- return receiveObject( Stream );
- }
-
- public object receiveObject( Stream stream )
- {
- object obj = new object();
-
- var formatter = m_formatter.getInstance();
-
- try
- {
- obj = formatter.Deserialize( stream );
- }
- catch( System.Xml.XmlException ex )
- {
- log.error( $"Outer Exception {ex.Message}" );
- }
-
- return obj;
- }
-
- public void send( object obj )
- {
-
- var formatter = m_formatter.getInstance();
-
- try
- {
- var ms = new MemoryStream( BufferSize );
- formatter.Serialize( ms, obj );
-
- //var str = System.Text.Encoding.Default.GetString( mm_buffer, 0, (int)ms.Position );
- //log.info( $"Sent data {str} of length {ms.Position}" );
- //log.info( $"Sent {obj}" );
-
- byte[] byteSize = BitConverter.GetBytes( (uint)ms.Position );
- m_streamNet.Write( byteSize, 0, 4 );
- m_streamNet.Write( ms.GetBuffer(), 0, (int)ms.Position );
-
- m_streamNet.Flush();
- }
- catch( Exception e )
- {
- log.warn( $"Exception sending obj {obj} of {e}" );
- throw;
- }
- }
-
- public virtual void receive( object obj )
- {
- if( m_proc != null )
- m_proc.process( obj );
- }
-
- Socket m_socket;
-
- NetworkStream m_streamNet;
-
- IProcess m_proc;
-
-
-
- //private BufferedStream m_streamBufIn;
- //private BufferedStream m_streamBufOut;
- }
-
-
-
-}
diff --git a/net/FSM.cs b/net/FSM.cs
deleted file mode 100644
index eb778bc..0000000
--- a/net/FSM.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-using System;
-
-
-
-namespace net;
-
-
-
-public class Context
-{
-
-}
-
-public class State
- where T : State
- where CTX : Context
-{
- virtual public void onEnter( CTX ctx, State oldState )
- {
- }
-
- virtual public void onExit( CTX ctx, State newState )
- {
- }
-}
-
-/*
-public class PotentialState : State
- where T : State
- where CTX : Context
-{
- virtual public void onEnter(CTX ctx, State oldState)
- {
- }
-
- virtual public void onExit(CTX ctx, State newState)
- {
- }
-}
-*/
-
-
-public class FSM
- where T : FSM
- where CTX : Context
- where ST : State
-{
- public CTX Context { get; private set; }
- public ST State { get; private set; }
-
- public FSM( CTX context, ST state )
- {
- Context = context;
- State = state;
- }
-
- public void Transition( ST newState )
- {
- }
-
-
-
-}
-
diff --git a/net/NetMsg.cs b/net/NetMsg.cs
deleted file mode 100644
index 5e77ecb..0000000
--- a/net/NetMsg.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-using System;
-
-namespace lib.Net
-{
- [Serializable]
- public class Msg
- {
- public Msg()
- {
- }
- }
-
- [Serializable]
- public class Login
- {
- public Login( String name, String pass )
- {
- m_username = name;
- m_password = pass;
- }
-
- public readonly String m_username;
- public readonly String m_password;
- }
-
- [Serializable]
- public class LoginResp
- {
- public LoginResp( bool resp )
- {
- m_resp = resp;
- }
-
- public readonly bool m_resp;
- }
-
- #region Admin Messages
- //Subclasses of this need to be on an admin client.
- [Serializable]
- public class Admin
- {
-
- };
-
- [Serializable]
- public class CreateEntity : Admin
- {
-
- }
-
-
- [Serializable]
- public class MoveEntity : Admin
- {
-
- }
- #endregion
-
- [Serializable]
- public class EntityBase
- {
- public EntityBase( int id )
- {
- m_id = id;
- }
-
- public readonly int m_id;
- };
-
-
- [Serializable]
- public class EntityPos : EntityBase
- {
- public EntityPos( int id, float x, float y, float z ) :
- base( id )
- {
- m_x = x;
- m_y = y;
- m_z = z;
- }
-
- public readonly float m_x;
- public readonly float m_y;
- public readonly float m_z;
- }
-
- [Serializable]
- public class EntityDesc : EntityBase
- {
- public EntityDesc( int id ) :
- base( id )
- {
- }
-
- //Should an entity have a mesh? Be made up of multiple meshes?
- public readonly String m_mesh;
- }
-
-
-
-
-
-}
diff --git a/prof/AddressStack.cs b/prof/AddressStack.cs
deleted file mode 100644
index bf57554..0000000
--- a/prof/AddressStack.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System.Collections.Generic;
-
-namespace Tracing
-{
- public class AddressStack
- {
- // the first frame is the address of the last called method
- private readonly List _stack;
-
- public AddressStack( int capacity )
- {
- _stack = new List( capacity );
- }
-
- // No need to override GetHashCode because we don't want to use it as a key in a dictionary
- public override bool Equals( object obj )
- {
- if( obj == null )
- return false;
-
- var stack = obj as AddressStack;
- if( stack == null )
- return false;
-
- var frameCount = _stack.Count;
- if( frameCount != stack._stack.Count )
- return false;
-
- for( int i = 0; i < frameCount; i++ )
- {
- if( _stack[i] != stack._stack[i] )
- return false;
- }
-
- return true;
- }
-
- public override int GetHashCode() => _stack.GetHashCode();
-
- public IReadOnlyList Stack => _stack;
-
- public void AddFrame( ulong address )
- {
- _stack.Add( address );
- }
- }
-}
diff --git a/prof/Memory.cs b/prof/Memory.cs
deleted file mode 100644
index 0cce0e0..0000000
--- a/prof/Memory.cs
+++ /dev/null
@@ -1,314 +0,0 @@
-using Microsoft.Diagnostics.Tracing;
-using Microsoft.Diagnostics.Tracing.Parsers;
-using Microsoft.Diagnostics.Tracing.Parsers.Clr;
-using Microsoft.Diagnostics.Tracing.Parsers.Kernel;
-using Microsoft.Diagnostics.Tracing.Session;
-using ProfilerHelpers;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Tracing
-{
- public class Memory
- {
- private readonly TraceEventSession _session;
- private readonly PerProcessProfilingState _processes;
-
- // because we are not interested in self monitoring
- private readonly int _currentPid;
-
- private int _started = 0;
-
- public Memory( TraceEventSession session, PerProcessProfilingState processes )
- {
- _session = session;
- _processes = processes;
- _currentPid = Process.GetCurrentProcess().Id;
- }
-
- public async Task StartAsync( bool allAllocations )
- {
- if( Interlocked.CompareExchange( ref _started, 1, 0 ) == 1 )
- {
- throw new InvalidOperationException( "Impossible to start profiling more than once." );
- }
-
- await Task.Factory.StartNew( () =>
- {
- using( _session )
- {
- log.info( $"SetupProviders" );
- SetupProviders( _session, allAllocations );
-
- log.info( $"SetupListeners" );
- SetupListeners( _session.Source );
-
- log.info( $"Source.Process()" );
- while( _session.Source.Process() )
- {
- Task.Delay( 1 );
- }
-
- log.info( $"Done" );
- }
- } );
- }
-
- private void SetupProviders( TraceEventSession session, bool noSampling )
- {
- // Note: the kernel provider MUST be the first provider to be enabled
- // If the kernel provider is not enabled, the callstacks for CLR events are still received
- // but the symbols are not found (except for the application itself)
- // Maybe a TraceEvent implementation details triggered when a module (image) is loaded
- var success = true;
-
- //*
- log.info( $"EnableKernelProvider" );
- success = log.var( session.EnableKernelProvider( KernelTraceEventParser.Keywords.None |
- // KernelTraceEventParser.Keywords.ImageLoad |
- // KernelTraceEventParser.Keywords.Process
- 0,
- KernelTraceEventParser.Keywords.None
- ) );
- log.info( $"EnableKernelProvider {success}" );
- //*/
-
- // The CLR source code indicates that the provider must be set before the monitored application starts
- // Note: no real difference between High and Low
- ClrTraceEventParser.Keywords eventsKeyword = noSampling
- ? ClrTraceEventParser.Keywords.GCSampledObjectAllocationLow | ClrTraceEventParser.Keywords.GCSampledObjectAllocationHigh
- : ClrTraceEventParser.Keywords.GCSampledObjectAllocationLow
- ;
-
- log.info( $"EnableProvider" );
- success = log.var( session.EnableProvider(
- ClrTraceEventParser.ProviderGuid,
- TraceEventLevel.Verbose, // this is needed in order to receive GCSampledObjectAllocation event
- (ulong)(
-
- eventsKeyword |
-
- // required to receive the BulkType events that allows
- // mapping between the type ID received in the allocation events
- ClrTraceEventParser.Keywords.GCHeapAndTypeNames |
- ClrTraceEventParser.Keywords.Type |
-
- // events related to JITed methods
- ClrTraceEventParser.Keywords.Jit | // Turning on JIT events is necessary to resolve JIT compiled code
- ClrTraceEventParser.Keywords.JittedMethodILToNativeMap | // This is needed if you want line number information in the stacks
- ClrTraceEventParser.Keywords.Loader | // You must include loader events as well to resolve JIT compiled code.
-
- // this is mandatory to get the callstacks in each CLR event payload.
- //ClrTraceEventParser.Keywords.Stack |
-
- 0
- )
- ) );
- log.info( $"EnableProvider {success}" );
-
-
- // Note: ClrRundown is not needed because only new processes will be monitored
- }
-
- private void SetupListeners( ETWTraceEventSource source )
- {
- // register for high and low keyword
- // if both are set, each allocation will trigger an event (beware performance issues...)
- source.Clr.GCSampledObjectAllocation += OnSampleObjectAllocation;
-
- // required to receive the mapping between type ID (received in GCSampledObjectAllocation)
- // and their name (received in TypeBulkType)
- source.Clr.TypeBulkType += OnTypeBulkType;
-
- // messages to get callstacks
- // the correlation seems to be as "simple" as taking the last event on the same thread
- source.Clr.ClrStackWalk += OnClrStackWalk;
-
- // needed to get JITed method details
- source.Clr.MethodLoadVerbose += OnMethodDetails;
- source.Clr.MethodDCStartVerboseV2 += OnMethodDetails;
-
- source.Clr.ContentionLockCreated += OnLockCreated;
- source.Clr.ContentionStart += OnLockStart;
- source.Clr.ContentionStop += OnLockStop;
-
- // get notified when a module is load to map the corresponding symbols
- source.Kernel.ImageLoad += OnImageLoad;
- }
-
- private void OnLockCreated( ContentionLockCreatedTraceData data )
- {
- }
-
- private void OnLockStart( ContentionStartTraceData data )
- {
-
- }
-
- private void OnLockStop( ContentionStopTraceData data )
- {
- }
-
- private void OnImageLoad( ImageLoadTraceData data )
- {
- if( FilterOutEvent( data ) )
- return;
-
- GetProcessMethods( data.ProcessID ).AddModule( data.FileName, data.ImageBase, data.ImageSize );
-
- log.info( $"{data.ProcessID}.{data.ThreadID} --> {data.FileName}" );
- }
-
- private void OnMethodDetails( MethodLoadUnloadVerboseTraceData data )
- {
- if( FilterOutEvent( data ) )
- return;
-
- // care only about jitted methods
- if( !data.IsJitted )
- return;
-
- var method = GetProcessMethods( data.ProcessID )
- .Add( data.MethodStartAddress, data.MethodSize, data.MethodNamespace, data.MethodName, data.MethodSignature );
-
- log.info( $"0x{data.MethodStartAddress.ToString( "x12" )} - {data.MethodSize,6} | {data.MethodName}" );
- }
-
- private MethodStore GetProcessMethods( int pid )
- {
- if( !_processes.Methods.TryGetValue( pid, out var methods ) )
- {
- methods = new MethodStore( pid );
- _processes.Methods[pid] = methods;
- }
- return methods;
- }
-
-
- private void OnSampleObjectAllocation( GCSampledObjectAllocationTraceData data )
- {
- if( FilterOutEvent( data ) )
- return;
-
- var typeName = GetProcessTypeName( data.ProcessID, data.TypeID );
- if( data.TotalSizeForTypeSample >= 85000 )
- {
- var message = $"{data.ProcessID}.{data.ThreadID} - {data.TimeStampRelativeMSec,12} | Alloc {GetProcessTypeName( data.ProcessID, data.TypeID )} ({data.TotalSizeForTypeSample})";
- log.info( message );
- }
- GetProcessAllocations( data.ProcessID )
- .AddAllocation(
- data.ThreadID,
- (ulong)data.TotalSizeForTypeSample,
- (ulong)data.ObjectCountForTypeSample,
- typeName
- );
- }
-
- private ProcessAllocations GetProcessAllocations( int pid )
- {
- if( !_processes.Allocations.TryGetValue( pid, out var allocations ) )
- {
- allocations = new ProcessAllocations( pid );
- _processes.Allocations[pid] = allocations;
- }
- return allocations;
- }
-
- private void OnClrStackWalk( ClrStackWalkTraceData data )
- {
- if( FilterOutEvent( data ) )
- return;
-
- //var message = $"{data.ProcessID}.{data.ThreadID} - {data.TimeStampRelativeMSec,12} | {data.FrameCount} frames";
- //log.info(message);
-
- var callstack = BuildCallStack( data );
- GetProcessAllocations( data.ProcessID ).AddStack( data.ThreadID, callstack );
- //DumpStack(data);
- }
-
- private AddressStack BuildCallStack( ClrStackWalkTraceData data )
- {
- var length = data.FrameCount;
- AddressStack stack = new AddressStack( length );
-
- // frame 0 is the last frame of the stack (i.e. last called method)
- for( int i = 0; i < length; i++ )
- {
- stack.AddFrame( data.InstructionPointer( i ) );
- }
-
- return stack;
- }
-
- private void DumpStack( ClrStackWalkTraceData data )
- {
- var methods = GetProcessMethods( data.ProcessID );
- for( int i = 0; i < data.FrameCount; i++ )
- {
- var address = data.InstructionPointer( i );
- log.info( methods.GetFullName( address ) );
- }
- log.info( $"" );
- }
-
- private void OnTypeBulkType( GCBulkTypeTraceData data )
- {
- if( FilterOutEvent( data ) )
- return;
-
- ProcessTypeMapping mapping = GetProcessTypesMapping( data.ProcessID );
- for( int currentType = 0; currentType < data.Count; currentType++ )
- {
- GCBulkTypeValues value = data.Values( currentType );
- mapping[value.TypeID] = value.TypeName;
- }
- }
-
- private ProcessTypeMapping GetProcessTypesMapping( int pid )
- {
- ProcessTypeMapping mapping;
- if( !_processes.Types.TryGetValue( pid, out mapping ) )
- {
- AssociateProcess( pid );
-
- mapping = new ProcessTypeMapping( pid );
- _processes.Types[pid] = mapping;
- }
- return mapping;
- }
-
- private void AssociateProcess( int pid )
- {
- try
- {
- _processes.Names[pid] = Process.GetProcessById( pid ).ProcessName;
- }
- catch( Exception )
- {
- log.info( $"? {pid}" );
- // we might not have access to the process
- }
- }
-
- private string GetProcessTypeName( int pid, ulong typeID )
- {
- if( !_processes.Types.TryGetValue( pid, out var mapping ) )
- {
- return typeID.ToString();
- }
-
- var name = mapping[typeID];
- return string.IsNullOrEmpty( name ) ? typeID.ToString() : name;
- }
-
- private bool FilterOutEvent( TraceEvent data )
- {
- return ( data.ProcessID == _currentPid );
- }
- }
-}
diff --git a/prof/MemoryPipe.cs b/prof/MemoryPipe.cs
deleted file mode 100644
index 01314d7..0000000
--- a/prof/MemoryPipe.cs
+++ /dev/null
@@ -1,393 +0,0 @@
-using Microsoft.Diagnostics.NETCore.Client;
-using Microsoft.Diagnostics.Tracing;
-using Microsoft.Diagnostics.Tracing.Etlx;
-using Microsoft.Diagnostics.Tracing.Parsers;
-using Microsoft.Diagnostics.Tracing.Parsers.Clr;
-using Microsoft.Diagnostics.Tracing.Parsers.Kernel;
-using Microsoft.Diagnostics.Tracing.Session;
-using ProfilerHelpers;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Diagnostics.Tracing;
-using System.Threading;
-using System.Threading.Tasks;
-using TraceKeywords = Microsoft.Diagnostics.Tracing.Parsers.ClrTraceEventParser.Keywords;
-
-namespace Tracing
-{
- public class MemoryPipe
- {
- private readonly DiagnosticsClient _client;
- private readonly PerProcessProfilingState _processes;
-
- // because we are not interested in self monitoring
- private readonly int _currentPid;
-
- private int _started = 0;
-
- Thread _thread;
-
- public MemoryPipe()
- {
-
- _currentPid = Process.GetCurrentProcess().Id;
-
- _client = new DiagnosticsClient( _currentPid );
-
- _processes = new();
-
-
- var threadStart = new ThreadStart( () => Start( true ) );
- _thread = new Thread( threadStart );
- _thread.Start();
-
-
- }
-
- //public async Task StartAsync( bool allAllocations )
- public void Start( bool allAllocations )
- {
- if( Interlocked.CompareExchange( ref _started, 1, 0 ) == 1 )
- {
- throw new InvalidOperationException( "Impossible to start profiling more than once." );
- }
-
- log.info( $"Starting MemoryPipe on thread {Thread.CurrentThread.ManagedThreadId}" );
-
- var providers = new List()
- {
- new EventPipeProvider("Microsoft-Windows-DotNETRuntime",
- EventLevel.Verbose, (long)(
- TraceKeywords.GC |
- TraceKeywords.Contention |
- TraceKeywords.Debugger |
- TraceKeywords.Exception |
- TraceKeywords.GCAllObjectAllocation |
- TraceKeywords.GCSampledObjectAllocationHigh |
- TraceKeywords.GCSampledObjectAllocationLow |
- TraceKeywords.Security |
- TraceKeywords.Threading |
- TraceKeywords.Type |
- TraceKeywords.TypeDiagnostic |
- TraceKeywords.WaitHandle |
- TraceKeywords.All
- ) )
- };
-
-
- //await Task.Factory.StartNew( () => {
- using EventPipeSession session = _client.StartEventPipeSession( providers, false );
-
- //log.info( $"SetupProviders" );
- //SetupProviders( session, allAllocations );
- var source = new EventPipeEventSource( session.EventStream );
-
-
- log.info( $"SetupListeners" );
- SetupListeners( source );
-
- log.info( $"Run Process" );
- source.Process();
-
- log.info( $"Done" );
- //} );
- }
-
- private void SetupProviders( TraceEventSession session, bool noSampling )
- {
- // Note: the kernel provider MUST be the first provider to be enabled
- // If the kernel provider is not enabled, the callstacks for CLR events are still received
- // but the symbols are not found (except for the application itself)
- // Maybe a TraceEvent implementation details triggered when a module (image) is loaded
- var success = true;
-
- //*
- log.info( $"EnableKernelProvider" );
- success = log.var( session.EnableKernelProvider( KernelTraceEventParser.Keywords.None |
- // KernelTraceEventParser.Keywords.ImageLoad |
- // KernelTraceEventParser.Keywords.Process
- 0,
- KernelTraceEventParser.Keywords.None
- ) );
- log.info( $"EnableKernelProvider {success}" );
- //*/
-
- // The CLR source code indicates that the provider must be set before the monitored application starts
- // Note: no real difference between High and Low
- ClrTraceEventParser.Keywords eventsKeyword = noSampling
- ? ClrTraceEventParser.Keywords.GCSampledObjectAllocationLow | ClrTraceEventParser.Keywords.GCSampledObjectAllocationHigh
- : ClrTraceEventParser.Keywords.GCSampledObjectAllocationLow
- ;
-
- log.info( $"EnableProvider" );
- success = log.var( session.EnableProvider(
- ClrTraceEventParser.ProviderGuid,
- TraceEventLevel.Verbose, // this is needed in order to receive GCSampledObjectAllocation event
- (ulong)(
-
- eventsKeyword |
-
- // required to receive the BulkType events that allows
- // mapping between the type ID received in the allocation events
- ClrTraceEventParser.Keywords.GCHeapAndTypeNames |
- ClrTraceEventParser.Keywords.Type |
-
- // events related to JITed methods
- ClrTraceEventParser.Keywords.Jit | // Turning on JIT events is necessary to resolve JIT compiled code
- ClrTraceEventParser.Keywords.JittedMethodILToNativeMap | // This is needed if you want line number information in the stacks
- ClrTraceEventParser.Keywords.Loader | // You must include loader events as well to resolve JIT compiled code.
-
- // this is mandatory to get the callstacks in each CLR event payload.
- //ClrTraceEventParser.Keywords.Stack |
-
- 0
- )
- ) );
- log.info( $"EnableProvider {success}" );
-
-
- // Note: ClrRundown is not needed because only new processes will be monitored
- }
-
- private void SetupListeners( EventPipeEventSource source )
- {
- // register for high and low keyword
- // if both are set, each allocation will trigger an event (beware performance issues...)
- //source.Clr.GCSampledObjectAllocation += OnSampleObjectAllocation;
- source.Clr.GCAllocationTick += OnAllocTick;
-
- // required to receive the mapping between type ID (received in GCSampledObjectAllocation)
- // and their name (received in TypeBulkType)
- source.Clr.TypeBulkType += OnTypeBulkType;
-
- // messages to get callstacks
- // the correlation seems to be as "simple" as taking the last event on the same thread
- source.Clr.ClrStackWalk += OnClrStackWalk;
-
- // needed to get JITed method details
- source.Clr.MethodLoadVerbose += OnMethodDetails;
- source.Clr.MethodDCStartVerboseV2 += OnMethodDetails;
-
- source.Clr.ContentionLockCreated += OnLockCreated;
- source.Clr.ContentionStart += OnLockStart;
- source.Clr.ContentionStop += OnLockStop;
-
- // get notified when a module is load to map the corresponding symbols
- source.Kernel.ImageLoad += OnImageLoad;
- }
-
- private void OnAllocTick( GCAllocationTickTraceData data )
- {
- if( FilterOutEvent( data ) )
- return;
-
- //log.info( $"*** RAW: {data}" );
-
- //var callStack = data.CallStack();
- //var caller = callStack.Caller;
-
- //log.info( $"Call stack {callStack}" );
-
- var thisThreadId = Thread.CurrentThread.ManagedThreadId;
-
- var typeName = GetProcessTypeName( data.ProcessID, data.TypeID );
- //if( data.TotalSizeForTypeSample >= 85000 )
- {
- var message = $"{data.ThreadID}/{thisThreadId} Alloc {data.ObjectSize,8} at 0x{data.Address:0000000000000000} in {data.TypeName} (or {GetProcessTypeName( data.ProcessID, data.TypeID )}) ";
- log.info( message );
- }
- GetProcessAllocations( data.ProcessID )
- .AddAllocation(
- data.ThreadID,
- (ulong)data.ObjectSize,
- (ulong)1,
- typeName
- );
- }
-
- private void OnLockCreated( ContentionLockCreatedTraceData data )
- {
- log.info( $"{data}" );
- }
-
- private void OnLockStart( ContentionStartTraceData data )
- {
- log.info( $"{data}" );
- }
-
- private void OnLockStop( ContentionStopTraceData data )
- {
- log.info( $"{data}" );
- }
-
- private void OnImageLoad( ImageLoadTraceData data )
- {
- //if( FilterOutEvent( data ) )
- // return;
-
- log.info( $"{data}" );
-
- //GetProcessMethods( data.ProcessID ).AddModule( data.FileName, data.ImageBase, data.ImageSize );
-
- log.info( $"{data.ProcessID}.{data.ThreadID} --> {data.FileName}" );
- }
-
- private void OnMethodDetails( MethodLoadUnloadVerboseTraceData data )
- {
- //if( FilterOutEvent( data ) )
- // return;
-
- //log.info( $"{data}" );
-
- // care only about jitted methods
- if( !data.IsJitted )
- return;
-
- var method = GetProcessMethods( data.ProcessID )
- .Add( data.MethodStartAddress, data.MethodSize, data.MethodNamespace, data.MethodName, data.MethodSignature );
-
- //log.info( $"0x{data.MethodStartAddress.ToString( "x12" )} - {data.MethodSize,6} | {data.MethodName}" );
- }
-
- private MethodStore GetProcessMethods( int pid )
- {
- if( !_processes.Methods.TryGetValue( pid, out var methods ) )
- {
- methods = new MethodStore( pid );
- _processes.Methods[pid] = methods;
- }
- return methods;
- }
-
-
- private void OnSampleObjectAllocation( GCSampledObjectAllocationTraceData data )
- {
- if( FilterOutEvent( data ) )
- return;
-
- //log.info( $"{data}" );
-
- var typeName = GetProcessTypeName( data.ProcessID, data.TypeID );
- //if( data.TotalSizeForTypeSample >= 85000 )
- {
- var message = $"{data.ProcessID}.{data.ThreadID} - {data.TimeStampRelativeMSec,12} | Alloc {GetProcessTypeName( data.ProcessID, data.TypeID )} ({data.TotalSizeForTypeSample})";
- log.info( message );
- }
- GetProcessAllocations( data.ProcessID )
- .AddAllocation(
- data.ThreadID,
- (ulong)data.TotalSizeForTypeSample,
- (ulong)data.ObjectCountForTypeSample,
- typeName
- );
- }
-
- private ProcessAllocations GetProcessAllocations( int pid )
- {
- if( !_processes.Allocations.TryGetValue( pid, out var allocations ) )
- {
- allocations = new ProcessAllocations( pid );
- _processes.Allocations[pid] = allocations;
- }
- return allocations;
- }
-
- private void OnClrStackWalk( ClrStackWalkTraceData data )
- {
- var message = $"{data.ProcessID}.{data.ThreadID} - {data.TimeStampRelativeMSec,12} | {data.FrameCount} frames";
- log.info( message );
-
- var callstack = BuildCallStack( data );
- GetProcessAllocations( data.ProcessID ).AddStack( data.ThreadID, callstack );
- //DumpStack(data);
- }
-
- private AddressStack BuildCallStack( ClrStackWalkTraceData data )
- {
- //log.info( $"{data}" );
-
- var length = data.FrameCount;
- AddressStack stack = new AddressStack( length );
-
- // frame 0 is the last frame of the stack (i.e. last called method)
- for( int i = 0; i < length; i++ )
- {
- stack.AddFrame( data.InstructionPointer( i ) );
- }
-
- return stack;
- }
-
- private void DumpStack( ClrStackWalkTraceData data )
- {
- if( FilterOutEvent( data ) )
- return;
-
- log.info( $"{data}" );
-
- var methods = GetProcessMethods( data.ProcessID );
- for( int i = 0; i < data.FrameCount; i++ )
- {
- var address = data.InstructionPointer( i );
- log.info( methods.GetFullName( address ) );
- }
- log.info( $"" );
- }
-
- private void OnTypeBulkType( GCBulkTypeTraceData data )
- {
-
- ProcessTypeMapping mapping = GetProcessTypesMapping( data.ProcessID );
- for( int currentType = 0; currentType < data.Count; currentType++ )
- {
- GCBulkTypeValues value = data.Values( currentType );
- mapping[value.TypeID] = value.TypeName;
- //log.info( $"{value}" );
- }
- }
-
- private ProcessTypeMapping GetProcessTypesMapping( int pid )
- {
- ProcessTypeMapping mapping;
- if( !_processes.Types.TryGetValue( pid, out mapping ) )
- {
- AssociateProcess( pid );
-
- mapping = new ProcessTypeMapping( pid );
- _processes.Types[pid] = mapping;
- }
- return mapping;
- }
-
- private void AssociateProcess( int pid )
- {
- try
- {
- _processes.Names[pid] = Process.GetProcessById( pid ).ProcessName;
- }
- catch( Exception )
- {
- log.info( $"? {pid}" );
- // we might not have access to the process
- }
- }
-
- private string GetProcessTypeName( int pid, ulong typeID )
- {
- if( !_processes.Types.TryGetValue( pid, out var mapping ) )
- {
- return typeID.ToString();
- }
-
- var name = mapping[typeID];
- return string.IsNullOrEmpty( name ) ? typeID.ToString() : name;
- }
-
- private bool FilterOutEvent( TraceEvent data )
- {
- return data.ThreadID == Thread.CurrentThread.ManagedThreadId;
- //return false; // ( data.ProcessID == _currentPid );
- }
- }
-}
diff --git a/prof/MethodInfo.cs b/prof/MethodInfo.cs
deleted file mode 100644
index 0facada..0000000
--- a/prof/MethodInfo.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using System;
-
-namespace ProfilerHelpers
-{
- public class MethodInfo
- {
- private readonly ulong _startAddress;
- private readonly int _size;
- private readonly string _fullName;
-
- internal MethodInfo( ulong startAddress, int size, string namespaceAndTypeName, string name, string signature )
- {
- _startAddress = startAddress;
- _size = size;
- _fullName = ComputeFullName( startAddress, namespaceAndTypeName, name, signature );
- }
-
- private string ComputeFullName( ulong startAddress, string namespaceAndTypeName, string name, string signature )
- {
- var fullName = signature;
-
- // constructor case: name = .ctor | namespaceAndTypeName = A.B.typeName | signature = ... (parameters)
- // --> A.B.typeName(parameters)
- if( name == ".ctor" )
- {
- return $"{namespaceAndTypeName}{ExtractParameters( signature )}";
- }
-
- // general case: name = Foo | namespaceAndTypeName = A.B.typeName | signature = ... (parameters)
- // --> A.B.Foo(parameters)
- fullName = $"{namespaceAndTypeName}.{name}{ExtractParameters( signature )}";
- return fullName;
- }
-
- private string ExtractTypeName( string namespaceAndTypeName )
- {
- var pos = namespaceAndTypeName.LastIndexOf( ".", StringComparison.Ordinal );
- if( pos == -1 )
- {
- return namespaceAndTypeName;
- }
-
- // skip the .
- pos++;
-
- return namespaceAndTypeName.Substring( pos );
- }
-
- private string ExtractParameters( string signature )
- {
- var pos = signature.IndexOf( " (" );
- if( pos == -1 )
- {
- return "(???)";
- }
-
- // skip double space
- pos += 2;
-
- var parameters = signature.Substring( pos );
- return parameters;
- }
-
- public ulong StartAddress => _startAddress;
- public int Size => _size;
- public string FullName => _fullName;
- }
-}
diff --git a/prof/MethodStore.cs b/prof/MethodStore.cs
deleted file mode 100644
index 9f09cc0..0000000
--- a/prof/MethodStore.cs
+++ /dev/null
@@ -1,209 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace ProfilerHelpers
-{
- public class MethodStore : IDisposable
- {
- // JITed methods information (start address + size + signature)
- private readonly List _methods;
-
- // addresses from callstacks already matching (address -> full name)
- private readonly Dictionary _cache;
-
- // for native methods, rely on dbghelp API
- // so the process handle is required
- private IntPtr _hProcess;
- private Process _process;
- private readonly int _pid;
-
- public MethodStore( int pid, bool loadModules = false )
- {
- // it may be possible to open the process
- // in that case, _hProcess = IntPtr.Zero
- _pid = pid;
-
- _methods = new List( 1024 );
- _cache = new Dictionary();
-
- _hProcess = BindToProcess( pid, loadModules );
- }
-
- private IntPtr BindToProcess( int pid, bool loadModules )
- {
- try
- {
- _process = Process.GetProcessById( pid );
-
- if( !SymInitialize( _process.Handle, loadModules ) )
- return IntPtr.Zero;
-
- return _process.Handle;
- }
- catch( Exception x )
- {
- Console.WriteLine( $"Error while binding pid #{pid} to DbgHelp:" );
- Console.WriteLine( x.Message );
- return IntPtr.Zero;
- }
- }
-
- private bool SymInitialize( IntPtr hProcess, bool loadModules = false )
- {
- // read https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symsetoptions for more details
- // maybe SYMOPT_NO_PROMPTS and SYMOPT_FAIL_CRITICAL_ERRORS could be used
- NativeDbgHelp.SymSetOptions(
- NativeDbgHelp.SYMOPT_DEFERRED_LOADS | // performance optimization
- NativeDbgHelp.SYMOPT_UNDNAME // C++ names are not mangled
- );
-
- // https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-syminitialize
- // search path for symbols:
- // - The current working directory of the application
- // - The _NT_SYMBOL_PATH environment variable
- // - The _NT_ALTERNATE_SYMBOL_PATH environment variable
- //
- // passing false as last parameter means that we will need to call SymLoadModule64
- // each time a module is loaded in the process
- return NativeDbgHelp.SymInitialize( hProcess, null, loadModules );
- }
-
- public MethodInfo Add( ulong address, int size, string namespaceAndTypeName, string name, string signature )
- {
- var method = new MethodInfo( address, size, namespaceAndTypeName, name, signature );
- _methods.Add( method );
- return method;
- }
-
- public string GetFullName( ulong address )
- {
- if( _cache.TryGetValue( address, out var fullName ) )
- return fullName;
-
- // look for managed methods
- for( int i = 0; i < _methods.Count; i++ )
- {
- var method = _methods[i];
-
- if( ( address >= method.StartAddress ) && ( address < method.StartAddress + (ulong)method.Size ) )
- {
- fullName = method.FullName;
- _cache[address] = fullName;
- return fullName;
- }
- }
-
- // look for native methods
- fullName = GetNativeMethodName( address );
- _cache[address] = fullName;
-
- return fullName;
- }
-
- private string GetNativeMethodName( ulong address )
- {
- var symbol = new NativeDbgHelp.SYMBOL_INFO();
- symbol.MaxNameLen = 1024;
- symbol.SizeOfStruct = (uint)Marshal.SizeOf( symbol ) - 1024; // char buffer is not counted
- // the ANSI version of SymFromAddr is called so each character is 1 byte long
-
- if( NativeDbgHelp.SymFromAddr( _hProcess, address, out var displacement, ref symbol ) )
- {
- var buffer = new StringBuilder( symbol.Name.Length );
-
- // remove weird "$##" at the end of some symbols
- var pos = symbol.Name.LastIndexOf( "$##" );
- if( pos == -1 )
- buffer.Append( symbol.Name );
- else
- buffer.Append( symbol.Name, 0, pos );
-
- // add offset if any
- if( displacement != 0 )
- buffer.Append( $"+0x{displacement}" );
-
- return buffer.ToString();
- }
-
- // default value is just the address in HEX
-#if DEBUG
- return ( $"0x{address:x} (SymFromAddr failed with 0x{Marshal.GetLastWin32Error():x})" );
-#else
- return $"0x{address:x}";
-#endif
-
- }
-
- const int ERROR_SUCCESS = 0;
- public void AddModule( string filename, ulong baseOfDll, int sizeOfDll )
- {
- var baseAddress = NativeDbgHelp.SymLoadModule64( _hProcess, IntPtr.Zero, filename, null, baseOfDll, (uint)sizeOfDll );
- if( baseAddress == 0 )
- {
- // should work if the same module is added more than once
- if( Marshal.GetLastWin32Error() == ERROR_SUCCESS )
- return;
-
- Console.WriteLine( $"SymLoadModule64 failed for {filename}" );
- }
- }
-
- public void Dispose()
- {
- if( _hProcess == IntPtr.Zero )
- return;
- _hProcess = IntPtr.Zero;
-
- _process.Dispose();
- }
- }
-
- internal static class NativeDbgHelp
- {
- // from C:\Program Files (x86)\Windows Kits\10\Debuggers\inc\dbghelp.h
- public const uint SYMOPT_UNDNAME = 0x00000002;
- public const uint SYMOPT_DEFERRED_LOADS = 0x00000004;
-
- [StructLayout( LayoutKind.Sequential )]
- public struct SYMBOL_INFO
- {
- public uint SizeOfStruct;
- public uint TypeIndex; // Type Index of symbol
- private ulong Reserved1;
- private ulong Reserved2;
- public uint Index;
- public uint Size;
- public ulong ModBase; // Base Address of module containing this symbol
- public uint Flags;
- public ulong Value; // Value of symbol, ValuePresent should be 1
- public ulong Address; // Address of symbol including base address of module
- public uint Register; // register holding value or pointer to value
- public uint Scope; // scope of the symbol
- public uint Tag; // pdb classification
- public uint NameLen; // Actual length of name
- public uint MaxNameLen;
- [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1024 )]
- public string Name;
- }
-
- [DllImport( "dbghelp.dll", SetLastError = true )]
- public static extern bool SymInitialize( IntPtr hProcess, string userSearchPath, bool invadeProcess );
-
- [DllImport( "dbghelp.dll", SetLastError = true )]
- public static extern uint SymSetOptions( uint symOptions );
-
- [DllImport( "dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi )]
- public static extern ulong SymLoadModule64( IntPtr hProcess, IntPtr hFile, string imageName, string moduleName, ulong baseOfDll, uint sizeOfDll );
-
- // use ANSI version to ensure the right size of the structure
- // read https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/ns-dbghelp-symbol_info
- [DllImport( "dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi )]
- public static extern bool SymFromAddr( IntPtr hProcess, ulong address, out ulong displacement, ref SYMBOL_INFO symbol );
-
- [DllImport( "dbghelp.dll", SetLastError = true )]
- public static extern bool SymCleanup( IntPtr hProcess );
- }
-}
diff --git a/prof/PerProcessProfilingState.cs b/prof/PerProcessProfilingState.cs
deleted file mode 100644
index 8a3c2d5..0000000
--- a/prof/PerProcessProfilingState.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using ProfilerHelpers;
-using System;
-using System.Collections.Generic;
-
-namespace Tracing
-{
- public class PerProcessProfilingState : IDisposable
- {
- private bool _disposed;
-
- private readonly Dictionary _processNames = new Dictionary();
- private readonly Dictionary _perProcessTypes = new Dictionary();
- private readonly Dictionary _perProcessAllocations = new Dictionary();
- private readonly Dictionary _methods = new Dictionary();
-
- public Dictionary Names => _processNames;
- public Dictionary Types => _perProcessTypes;
- public Dictionary Allocations => _perProcessAllocations;
- public Dictionary Methods => _methods;
-
- public void Dispose()
- {
- if( _disposed )
- return;
- _disposed = true;
-
- foreach( var methodStore in _methods.Values )
- {
- methodStore.Dispose();
- }
- }
- }
-}
diff --git a/prof/ProcessAllocations.cs b/prof/ProcessAllocations.cs
deleted file mode 100644
index acdc4dd..0000000
--- a/prof/ProcessAllocations.cs
+++ /dev/null
@@ -1,131 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Tracing
-{
-
- public class ProcessAllocations
- {
- private readonly int _pid;
- private readonly Dictionary _allocations;
- private readonly Dictionary _perThreadLastAllocation;
-
- public ProcessAllocations( int pid )
- {
- _pid = pid;
- _allocations = new Dictionary();
- _perThreadLastAllocation = new Dictionary();
- }
-
- public int Pid => _pid;
-
- public AllocationInfo GetAllocations( string typeName )
- {
- return ( _allocations.TryGetValue( typeName, out var info ) ) ? info : null;
- }
-
- public IEnumerable GetAllAllocations()
- {
- return _allocations.Values;
- }
-
- public AllocationInfo AddAllocation( int threadID, ulong size, ulong count, string typeName )
- {
- if( !_allocations.TryGetValue( typeName, out var info ) )
- {
- info = new AllocationInfo( typeName );
- _allocations[typeName] = info;
- }
-
- info.AddAllocation( size, count );
-
- // the last allocation is still here without the corresponding stack
- if( _perThreadLastAllocation.TryGetValue( threadID, out var lastAlloc ) )
- {
- Console.WriteLine( "no stack for the last allocation" );
- }
-
- // keep track of the allocation for the given thread
- // --> will be used when the corresponding call stack event will be received
- _perThreadLastAllocation[threadID] = info;
-
- return info;
- }
-
- public void AddStack( int threadID, AddressStack stack )
- {
- if( _perThreadLastAllocation.TryGetValue( threadID, out var lastAlloc ) )
- {
- lastAlloc.AddStack( stack );
- _perThreadLastAllocation.Remove( threadID );
- return;
- }
-
- //Console.WriteLine("no last allocation for the stack event");
- }
- }
-
-
- public class AllocationInfo
- {
- private readonly string _typeName;
- private ulong _size;
- private ulong _count;
- private List _stacks;
-
- internal AllocationInfo( string typeName )
- {
- _typeName = typeName;
- _stacks = new List();
- }
-
- public string TypeName => _typeName;
- public ulong Count => _count;
- public ulong Size => _size;
- public IReadOnlyList Stacks => _stacks;
-
- internal void AddAllocation( ulong size, ulong count )
- {
- _count += count;
- _size += size;
- }
-
- internal void AddStack( AddressStack stack )
- {
- var info = GetInfo( stack );
- if( info == null )
- {
- info = new StackInfo( stack );
- _stacks.Add( info );
- }
-
- info.Count++;
- }
-
- private StackInfo GetInfo( AddressStack stack )
- {
- for( int i = 0; i < _stacks.Count; i++ )
- {
- var info = _stacks[i];
- if( stack.Equals( info.Stack ) )
- return info;
- }
-
- return null;
- }
- }
-
- public class StackInfo
- {
- private readonly AddressStack _stack;
- public ulong Count;
-
- internal StackInfo( AddressStack stack )
- {
- Count = 0;
- _stack = stack;
- }
-
- public AddressStack Stack => _stack;
- }
-}
diff --git a/prof/ProcessTypeMapping.cs b/prof/ProcessTypeMapping.cs
deleted file mode 100644
index 81574cb..0000000
--- a/prof/ProcessTypeMapping.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System.Collections.Generic;
-
-namespace Tracing
-{
- // Contains the mapping between type ID received by SampleObjectAllocation(Low/High) events
- // and their name received by TypeBulkType events
- public class ProcessTypeMapping
- {
- private readonly Dictionary _typesIdToName;
-
- public ProcessTypeMapping( int processId )
- {
- ProcessId = processId;
- _typesIdToName = new Dictionary();
- }
-
- public int ProcessId { get; set; }
-
- public string this[ulong id]
- {
- get
- {
- if( !_typesIdToName.ContainsKey( id ) )
- return null;
-
- return _typesIdToName[id];
- }
- set
- {
- _typesIdToName[id] = value;
- }
- }
-
- }
-}
diff --git a/prof/Program.cs b/prof/Program.cs
deleted file mode 100644
index 1403092..0000000
--- a/prof/Program.cs
+++ /dev/null
@@ -1,162 +0,0 @@
-using Microsoft.Diagnostics.Tracing.Session;
-using ProfilerHelpers;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Tracing
-{
- static class Program
- {
-
-
- static public int CreateTracingSession( bool noSampling, bool sortBySize, int topTypesLimit )
- {
- ShowHeader();
-
- try
- {
-
- TraceEventSession session = new TraceEventSession(
- "Tracing",
- TraceEventSessionOptions.Create
- );
-
- log.info( $"Create PerProcessProfilingState" );
-
- using( var processes = new PerProcessProfilingState() )
- {
- log.info( $"Create Memory profiler for session" );
- var profiler = new Memory( session, processes );
-
- log.info( $"Start task" );
- var task = profiler.StartAsync( noSampling );
-
- /*
- log.info( $"await the Continue" );
- await task.ContinueWith( ( t ) => {
- log.info( $"Task is done, Dispose" );
- session.Dispose();
- } );
- */
-
- //log.info("Press ENTER to stop memory profiling");
- //Console.ReadLine();
-
- /*
- try
- {
- await task;
- ShowResults( processes, sortBySize, topTypesLimit );
-
- return 0;
- }
- catch( Exception x )
- {
- log.info( x.Message );
- ShowHelp();
- }
- */
- }
-
- return -1;
- }
- catch( Exception x )
- {
- log.info( x.Message );
- ShowHelp();
- }
-
- return -2;
- }
-
- private static void ShowResults( PerProcessProfilingState processes, bool sortBySize, int topTypesLimit )
- {
- foreach( var pid in processes.Allocations.Keys )
- {
- // skip processes without symbol resolution
- if( !processes.Methods.ContainsKey( pid ) )
- continue;
-
- // skip processes without allocations
- if( !processes.Allocations[pid].GetAllAllocations().Any() )
- continue;
-
- ShowResults( GetProcessName( pid, processes.Names ), processes.Methods[pid], processes.Allocations[pid], sortBySize, topTypesLimit );
- }
- }
-
- private static string GetProcessName( int pid, Dictionary names )
- {
- if( names.TryGetValue( pid, out var name ) )
- return name;
-
- return pid.ToString();
- }
-
- private static void ShowResults( string name, MethodStore methods, ProcessAllocations allocations, bool sortBySize, int topTypesLimit )
- {
- log.info( $"Memory allocations for {name}" );
- log.info( $"" );
- log.info( "---------------------------------------------------------" );
- log.info( " Count Size Type" );
- log.info( "---------------------------------------------------------" );
- IEnumerable types = ( sortBySize )
- ? allocations.GetAllAllocations().OrderByDescending( a => a.Size )
- : allocations.GetAllAllocations().OrderByDescending( a => a.Count )
- ;
- if( topTypesLimit != -1 )
- types = types.Take( topTypesLimit );
-
- foreach( var allocation in types )
- {
- log.info( $"{allocation.Count,9} {allocation.Size,11} {allocation.TypeName}" );
-
- log.info( $"" );
- DumpStacks( allocation, methods );
- log.info( $"" );
- }
- log.info( $"" );
- log.info( $"" );
- }
-
- private static void DumpStacks( AllocationInfo allocation, MethodStore methods )
- {
- var stacks = allocation.Stacks.OrderByDescending( s => s.Count ).Take( 10 );
- foreach( var stack in stacks )
- {
- log.info( $"{stack.Count,6} allocations" );
- log.info( "----------------------------------" );
- DumpStack( stack.Stack, methods );
- log.info( $"" );
- }
- }
-
- private static void DumpStack( AddressStack stack, MethodStore methods )
- {
- var callstack = stack.Stack;
- for( int i = 0; i < Math.Min( 10, callstack.Count ); i++ )
- {
- log.info( $" {methods.GetFullName( callstack[i] )}" );
- }
- }
-
- private static void ShowHeader()
- {
- log.info( "Tracing v1.0.0 - Sampled memory profiler for .NET applications" );
- log.info( "by Christophe Nasarre" );
- log.info( $"" );
- }
- private static void ShowHelp()
- {
- log.info( $"" );
- log.info( "Tracing shows sampled allocations of a given .NET application." );
- log.info( "Usage: Tracing [-a (all allocations)] [-c (sort by count instead of default by size)] [-t ]" );
- log.info( " Ex: Tracing -t -1 (all types sampled allocations sorted by size)" );
- log.info( " Ex: Tracing -c -t 10 (allocations for top 10 types sorted by count)" );
- log.info( $"" );
- }
- }
-}
diff --git a/ser/XmlSer.cs b/ser/XmlSer.cs
deleted file mode 100644
index 156422e..0000000
--- a/ser/XmlSer.cs
+++ /dev/null
@@ -1,838 +0,0 @@
-using System;
-using System.IO;
-using System.Xml;
-using System.Runtime.Serialization;
-using System.Collections;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Linq;
-using System.Collections.Immutable;
-using System.Net.Sockets;
-using System.Collections.Concurrent;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Linq.Expressions;
-
-namespace ser;
-
-#region Attributes & Enums (Mostly unchanged, ensure these exist)
-
-/*
-
-public CoolClass
-{
- private string Rare = "Rare Change";
- private float TestF = 1.0f;
-}
-
-public class Bag
-{
- public string Owner { get; set; }
- public CoolClass Cool { get; set; } = new();
-}
-public class BasicTest
-{
- public Bag MyBag { get; set; } = new();
-}
-
-
-
-
-
-
-
-
-
-public abstract class Item
-{
- public int Id { get; set; }
-}
-
-public class Key : Item
-{
- public int Code { get; set; }
-}
-
-public class Orb : Item
-{
- private float Power = 1.0f;
- public bool IsDark = true;
-}
-
-
-
-
-*/
-
-public interface I_Serialize
-{
- void OnSerialize() { }
- object OnDeserialize( object enclosing ) => this;
-}
-
-
-[Flags]
-public enum Types
-{
- Fields = 0b_0001,
- Props = 0b_0010,
- Implied = 0b_0100,
- Explicit = 0b_1000,
-
-
- None = 0b_0000,
- Default = Fields,
- All = Fields | Props,
-}
-
-public class Ser : Attribute
-{
- public Types Types { get; set; } = Types.Default;
-}
-
-public class Do : Attribute
-{
-}
-
-public class Dont : Attribute
-{
-}
-
-
-public class ChildAttribute : Attribute
-{
- public string[] Values { get; private set; }
-
- public ChildAttribute( params string[] values )
- {
- this.Values = values;
- }
-}
-
-public class ChildFieldsAttribute : ChildAttribute
-{
- public ChildFieldsAttribute( params string[] values ) : base( values ) { }
-}
-
-public class ChildPropsAttribute : ChildAttribute
-{
- public ChildPropsAttribute( params string[] values ) : base( values ) { }
-}
-
-
-
-public interface ITypeHandler
-{
- bool CanHandle( TypeInfo typeInfo, XmlElement? elem = null ); // Elem needed for Deser
- void WriteXml( XmlSer xml, XmlWriter writer, object? obj, string name, Type memberType, bool forceType );
- object? ReadXml( XmlSer xml, XmlElement elem, Type expectedType, object? existing );
-}
-
-
-
-// --- Enums & Records (Slightly adjusted/renamed) ---
-public enum Datastructure { Tree, Graph }
-public enum BackingFieldNaming { Short, Regular }
-public enum POD { Attributes, Elements }
-public record struct TypeProxy( Func fnSer, Func fnDes );
-
-public record XmlCfg : io.Recorded
-{
- public bool Verbose { get; init; } = false;
- public Datastructure Structure { get; init; } = Datastructure.Tree;
- public int Version { get; init; } = 2;
- public ImmutableDictionary Proxies { get; init; } = ImmutableDictionary.Empty;
- public BackingFieldNaming Naming { get; init; } = BackingFieldNaming.Short;
- public POD POD { get; init; } = POD.Attributes;
- public ser.Types TypesDefault { get; init; } = ser.Types.Fields;
- public static XmlCfg Default { get; } = new XmlCfg();
-}
-
-#endregion
-
-#region Reflection & Metadata Cache
-
-public record DependentMember(
- string Name, //Prop or field name
- TypeInfo Enclosing,
- MemberInfo EnclosingMember
-);
-
-public enum MemberMetaType
-{
- Invalid,
- Simple,
- Composite,
-}
-
-public record MemberMeta(
- //Base type.
- Type Type,
- MemberInfo Info,
- string XmlName,
- Func GetValue,
- Action SetValue,
- bool IsPodAttribute,
- bool HasDo,
- bool HasDont
-);
-
-public record TypeInfo(
- Type Type,
- List Members,
- bool IsISerializable,
- bool IsImm,
- bool IsProxy,
- TypeProxy? ProxyDef
-);
-
-public class TypeMetaCache
-{
- private readonly ConcurrentDictionary _cache = new();
- private readonly XmlCfg _cfg;
-
- public TypeMetaCache( XmlCfg cfg ) => _cfg = cfg;
-
- public TypeInfo Get( Type type )
- {
- // Expanded in anticpation of more complex ways to specify saves/loads
-
- if( _cache.TryGetValue( type, out var ti ) )
- return ti;
-
- var children = new HashSet();
-
- var tiNew = BuildTypeInfo( type, children );
- _cache.AddOrUpdate( type, tiNew, ( t, ti ) => tiNew );
-
- return tiNew;
- }
-
- // Helper to create accessors (using standard reflection - can be optimized)
- private static Func CreateGetter( MemberInfo mi )
- {
- if( mi is FieldInfo fi )
- return fi.GetValue;
- if( mi is PropertyInfo pi && pi.CanRead )
- return pi.GetValue;
- return _ => null;
- }
-
- private static Action CreateSetter( MemberInfo mi )
- {
- if( mi is FieldInfo fi )
- return fi.SetValue;
- if( mi is PropertyInfo pi && pi.CanWrite )
- return pi.SetValue;
- return ( _, _ ) => { };
- }
-
-
- // Helper to create accessors (using standard reflection - can be optimized)
- private static Func CreateGetter( MemberInfo mi, Func getter )
- {
- if( mi is FieldInfo fi )
- {
- var innerGet = fi.GetValue;
-
- return obj => innerGet( getter( obj ) );
- }
-
- if( mi is PropertyInfo pi && pi.CanRead )
- {
- Func innerGet = pi.GetValue;
-
- return obj => innerGet( getter( obj ) );
- }
-
- // return pi.GetValue;
-
-
- return _ => null;
- }
-
- private static Action CreateSetter( MemberInfo mi, Func getter )
- {
- if( mi is FieldInfo fi )
- {
- Action innerSet = fi.SetValue;
-
- return ( obj, value ) => innerSet( getter( obj ), value );
- }
-
-
- if( mi is PropertyInfo pi && pi.CanWrite )
- {
- Action innerSet = pi.SetValue;
-
- //return innerSet;
-
- //var innerSetType = innerSet.GetType();
- //var isArgs = innerSetType.Metho
-
-
- return ( obj, value ) =>
- {
- var leaf = getter( obj );
- innerSet( leaf, value );
- };
- }
-
- return ( _, _ ) => { };
- }
-
-
- public void AddType( Type type, params string[] children )
- {
- var hashChildren = new HashSet( children );
-
- BuildTypeInfo( type, hashChildren );
- }
-
- private TypeInfo BuildTypeInfo( Type type, HashSet children )
- {
- if( _cfg.Verbose )
- log.info( $"Building TypeInfo for {type.Name}" );
-
- var members = new List();
- bool doImpls, doFields, doProps;
-
- GetFilters( _cfg.TypesDefault, type, out doImpls, out doFields, out doProps );
-
-
- var isImm = typeof( io.Obj ).IsAssignableFrom( type );
-
- var typesAtt = type.GetCustomAttribute( true );
- var serTypes = typesAtt?.Types ?? ser.Types.None;
-
-
- if( doFields || doImpls )
- {
- foreach( var fi in refl.GetAllFields( type ) )
- {
- ProcessMember( fi, serTypes.HasFlag( ser.Types.Fields ), children, doImpls, isImm, members );
- }
-
-
- }
-
- if( doProps || doImpls )
- {
- foreach( var pi in refl.GetAllProperties( type ) )
- {
- ProcessMember( pi, serTypes.HasFlag( ser.Types.Props ), children, doImpls, isImm, members );
- }
- }
-
- var (isProxy, proxyDef) = FindProxy( type );
-
- //Dont need to sort since we just run through the attributes first, then the nodes
- //members.Sort( ( a, b ) => ( a.IsPodAttribute.Int < b.IsPodAttribute.Int ) ? 1 : -1);
-
- return new TypeInfo(
- type,
- members,
- typeof( ISerializable ).IsAssignableFrom( type ) && !typeof( Delegate ).IsAssignableFrom( type ), // Exclude Delegates
- isImm,
- isProxy,
- proxyDef
- );
-
- }
-
- private (bool, TypeProxy?) FindProxy( Type type )
- {
- var tryType = type;
- while( tryType != null && tryType != typeof( object ) )
- {
- if( _cfg.Proxies.TryGetValue( tryType, out var proxy ) )
- {
- return (true, proxy);
- }
- tryType = tryType.BaseType;
- }
- return (false, null);
- }
-
-
-
-
-
-
- private void ProcessMember( MemberInfo mi, bool doMemberType, HashSet childrenOverridden, bool doImpls, bool isImm, List members )
- {
- List children = new( childrenOverridden );
- var (hasDo, hasDont, hasImpl, propName, serTypess) = GetMemberAttributes( mi, out var actualMiForAtts, children );
-
- if( hasDont )
- return;
-
- // TODO MH Change this to a configurable query(s)
- if( isImm && ( mi.Name == "MetaStorage" || mi.Name == "Fn" ) )
- return;
-
-
- if( mi.GetCustomAttribute( true ) != null )
- return;
-
- if( !(
- hasDo |
- doMemberType |
- ( hasImpl & children.Any() )
- ) )
- return;
-
-
- var miType = ( mi is FieldInfo fi ) ? fi.FieldType : ( (PropertyInfo)mi ).PropertyType; // CHANGED (moved up)
-
- string name = mi.Name;
- string finalName = name;
-
- if( !string.IsNullOrEmpty( propName ) )
- {
- finalName = ( _cfg.Naming == BackingFieldNaming.Short ) ? propName : name;
- }
-
- finalName = refl.TypeToIdentifier( finalName ); // Ensure XML-safe name
-
- var overiddenName = false;
-
- var getter = CreateGetter( mi );
- var setter = CreateSetter( mi );
-
- var blankHashSet = new HashSet