[GH-ISSUE #24] Poor performance #21

Closed
opened 2026-02-25 21:30:28 +03:00 by kerem · 6 comments
Owner

Originally created by @stevenxi on GitHub (Jun 29, 2016).
Original GitHub issue: https://github.com/brutaldev/StrongNameSigner/issues/24

Originally assigned to: @brutaldev on GitHub.

Hi,

I've tried to sign big batch of assemblies in one go (400+). It doesn't finish within 30 mins.

I've add an extra method in SigningHelper to solve this issue: it allows you solve references as join rather than 2 loop matching

public static void FixAssemblyReferences(IEnumerable<string> assemblyPaths, IEnumerable<string> signedAssemblyPaths,  string keyPath, string keyFilePassword, Action<string> info, Action<string> warning, Action<string> error, params string[] probingPaths)
{

    var assemblies = assemblyPaths.Where(x => !string.IsNullOrWhiteSpace(x) && File.Exists(x)).Distinct()
    .Select(p =>
    {

        AssemblyDefinition assembly = null;

        try
        {
            assembly = AssemblyDefinition.ReadAssembly(p, GetReadParameters(p, probingPaths));
            if (assembly.Name.PublicKeyToken == null || assembly.Name.PublicKeyToken.Length == 0)
                assembly = null;
        }
        catch (BadImageFormatException bife)
        {
            warning(string.Format("Warning: {0}", bife.Message));
        }
        catch (Exception ex)
        {
            error(string.Format("Error: {0}", ex.Message));
        }

        return new {Assembly = assembly, Path = p};
    }).Where(x=>x.Assembly != null).ToList();

    var signedAssemblies = signedAssemblyPaths.Where(x => !string.IsNullOrWhiteSpace(x) && File.Exists(x)).Distinct()
        .Select(p =>
        {

            AssemblyDefinition assembly = null;

            try
            {
                assembly = AssemblyDefinition.ReadAssembly(p, GetReadParameters(p, probingPaths));
                if (assembly.Name.PublicKeyToken == null || assembly.Name.PublicKeyToken.Length == 0)
                    assembly = null;
            }
            catch (BadImageFormatException bife)
            {
                warning(string.Format("Warning: {0}", bife.Message));
            }
            catch (Exception ex)
            {
                error(string.Format("Error: {0}", ex.Message));
            }

            return new { Assembly = assembly, Path = p };
        }).Where(x => x.Assembly != null).ToList();

    var toFixReferencePair = assemblies.SelectMany(a => a.Assembly.MainModule.AssemblyReferences.Select(r => new {Assembly = a, Ref = r})).ToList()
        .Join(signedAssemblies, x => new {x.Ref.Name, x.Ref.Version}, y => new {y.Assembly.Name.Name, y.Assembly.Name.Version}, (x, y) => new {a = x.Assembly.Assembly, b = y.Assembly, assemblyPath = x.Assembly.Path, refPath = y.Path, x.Ref})
        .Distinct();

    foreach (var pair in toFixReferencePair)
    {
        try
        {
            // Found a matching reference, let's set the public key token.
            if (BitConverter.ToString(pair.Ref.PublicKeyToken) != BitConverter.ToString(pair.b.Name.PublicKeyToken))
            {
                pair.Ref.PublicKeyToken = pair.b.Name.PublicKeyToken ?? new byte[0];
                pair.Ref.Version = pair.b.Name.Version;

                // Save and resign.
                pair.a.Write(pair.assemblyPath, new WriterParameters { StrongNameKeyPair = GetStrongNameKeyPair(keyPath, keyFilePassword), WriteSymbols = File.Exists(Path.ChangeExtension(pair.assemblyPath, ".pdb")) });

                info(string.Format("References to '{1}' in '{0}' were fixed successfully.", pair.assemblyPath, pair.refPath));
            }
        }
        catch (BadImageFormatException bife)
        {
            warning(string.Format("Warning: {0}", bife.Message));
        }
        catch (Exception ex)
        {
            error(string.Format("Error: {0}", ex.Message));
        }

    }


    var friendReferences = signedAssemblies.Select(x => new {Assembly = x, Attrs = x.Assembly.CustomAttributes.Where(attr => attr.AttributeType.FullName == typeof (InternalsVisibleToAttribute).FullName).ToList()})
        .SelectMany(x => x.Attrs.Select(y => new {x.Assembly, Attr = y})).ToList()
        .Join(assemblies, x => x.Attr.ConstructorArguments[0].Value.ToString(), y => y.Assembly.Name.Name, (x, y) => new {b = x.Assembly.Assembly, refPath = x.Assembly.Path, a = y, FriendRef = x.Attr})
        .Where(x => x.a.Assembly.Name.HasPublicKey).Distinct();

    foreach (var pair in friendReferences)
    {
        try
        {
            // Add the public key to the attribute.
            var typeRef = pair.FriendRef.ConstructorArguments[0].Type;
            pair.FriendRef.ConstructorArguments.Clear();
            pair.FriendRef.ConstructorArguments.Add(new CustomAttributeArgument(typeRef, pair.a.Assembly.Name.Name + ", PublicKey=" + BitConverter.ToString(pair.a.Assembly.Name.PublicKey).Replace("-", string.Empty)));

            // Save and resign.
            pair.b.Write(pair.refPath, new WriterParameters { StrongNameKeyPair = GetStrongNameKeyPair(keyPath, keyFilePassword), WriteSymbols = File.Exists(Path.ChangeExtension(pair.refPath, ".pdb")) });
            info(string.Format("References to '{1}' in '{0}' were fixed successfully.", pair.a.Path, pair.refPath));
         }
            catch (BadImageFormatException bife)
        {
            warning(string.Format("Warning: {0}", bife.Message));
        }
        catch (Exception ex)
        {
            error(string.Format("Error: {0}", ex.Message));
        }
    }
}
Originally created by @stevenxi on GitHub (Jun 29, 2016). Original GitHub issue: https://github.com/brutaldev/StrongNameSigner/issues/24 Originally assigned to: @brutaldev on GitHub. Hi, I've tried to sign big batch of assemblies in one go (400+). It doesn't finish within 30 mins. I've add an extra method in SigningHelper to solve this issue: it allows you solve references as join rather than 2 loop matching ``` public static void FixAssemblyReferences(IEnumerable<string> assemblyPaths, IEnumerable<string> signedAssemblyPaths, string keyPath, string keyFilePassword, Action<string> info, Action<string> warning, Action<string> error, params string[] probingPaths) { var assemblies = assemblyPaths.Where(x => !string.IsNullOrWhiteSpace(x) && File.Exists(x)).Distinct() .Select(p => { AssemblyDefinition assembly = null; try { assembly = AssemblyDefinition.ReadAssembly(p, GetReadParameters(p, probingPaths)); if (assembly.Name.PublicKeyToken == null || assembly.Name.PublicKeyToken.Length == 0) assembly = null; } catch (BadImageFormatException bife) { warning(string.Format("Warning: {0}", bife.Message)); } catch (Exception ex) { error(string.Format("Error: {0}", ex.Message)); } return new {Assembly = assembly, Path = p}; }).Where(x=>x.Assembly != null).ToList(); var signedAssemblies = signedAssemblyPaths.Where(x => !string.IsNullOrWhiteSpace(x) && File.Exists(x)).Distinct() .Select(p => { AssemblyDefinition assembly = null; try { assembly = AssemblyDefinition.ReadAssembly(p, GetReadParameters(p, probingPaths)); if (assembly.Name.PublicKeyToken == null || assembly.Name.PublicKeyToken.Length == 0) assembly = null; } catch (BadImageFormatException bife) { warning(string.Format("Warning: {0}", bife.Message)); } catch (Exception ex) { error(string.Format("Error: {0}", ex.Message)); } return new { Assembly = assembly, Path = p }; }).Where(x => x.Assembly != null).ToList(); var toFixReferencePair = assemblies.SelectMany(a => a.Assembly.MainModule.AssemblyReferences.Select(r => new {Assembly = a, Ref = r})).ToList() .Join(signedAssemblies, x => new {x.Ref.Name, x.Ref.Version}, y => new {y.Assembly.Name.Name, y.Assembly.Name.Version}, (x, y) => new {a = x.Assembly.Assembly, b = y.Assembly, assemblyPath = x.Assembly.Path, refPath = y.Path, x.Ref}) .Distinct(); foreach (var pair in toFixReferencePair) { try { // Found a matching reference, let's set the public key token. if (BitConverter.ToString(pair.Ref.PublicKeyToken) != BitConverter.ToString(pair.b.Name.PublicKeyToken)) { pair.Ref.PublicKeyToken = pair.b.Name.PublicKeyToken ?? new byte[0]; pair.Ref.Version = pair.b.Name.Version; // Save and resign. pair.a.Write(pair.assemblyPath, new WriterParameters { StrongNameKeyPair = GetStrongNameKeyPair(keyPath, keyFilePassword), WriteSymbols = File.Exists(Path.ChangeExtension(pair.assemblyPath, ".pdb")) }); info(string.Format("References to '{1}' in '{0}' were fixed successfully.", pair.assemblyPath, pair.refPath)); } } catch (BadImageFormatException bife) { warning(string.Format("Warning: {0}", bife.Message)); } catch (Exception ex) { error(string.Format("Error: {0}", ex.Message)); } } var friendReferences = signedAssemblies.Select(x => new {Assembly = x, Attrs = x.Assembly.CustomAttributes.Where(attr => attr.AttributeType.FullName == typeof (InternalsVisibleToAttribute).FullName).ToList()}) .SelectMany(x => x.Attrs.Select(y => new {x.Assembly, Attr = y})).ToList() .Join(assemblies, x => x.Attr.ConstructorArguments[0].Value.ToString(), y => y.Assembly.Name.Name, (x, y) => new {b = x.Assembly.Assembly, refPath = x.Assembly.Path, a = y, FriendRef = x.Attr}) .Where(x => x.a.Assembly.Name.HasPublicKey).Distinct(); foreach (var pair in friendReferences) { try { // Add the public key to the attribute. var typeRef = pair.FriendRef.ConstructorArguments[0].Type; pair.FriendRef.ConstructorArguments.Clear(); pair.FriendRef.ConstructorArguments.Add(new CustomAttributeArgument(typeRef, pair.a.Assembly.Name.Name + ", PublicKey=" + BitConverter.ToString(pair.a.Assembly.Name.PublicKey).Replace("-", string.Empty))); // Save and resign. pair.b.Write(pair.refPath, new WriterParameters { StrongNameKeyPair = GetStrongNameKeyPair(keyPath, keyFilePassword), WriteSymbols = File.Exists(Path.ChangeExtension(pair.refPath, ".pdb")) }); info(string.Format("References to '{1}' in '{0}' were fixed successfully.", pair.a.Path, pair.refPath)); } catch (BadImageFormatException bife) { warning(string.Format("Warning: {0}", bife.Message)); } catch (Exception ex) { error(string.Format("Error: {0}", ex.Message)); } } } ```
kerem 2026-02-25 21:30:28 +03:00
Author
Owner

@brutaldev commented on GitHub (Jun 29, 2016):

Please create a pull request for this change.

<!-- gh-comment-id:229412636 --> @brutaldev commented on GitHub (Jun 29, 2016): Please create a pull request for this change.
Author
Owner

@stevenxi commented on GitHub (Jun 29, 2016):

Have no git client here. And I'm not familiar with git.

On Wed, Jun 29, 2016 at 5:32 PM, Werner van Deventer <
notifications@github.com> wrote:

Please create a pull request for this change.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/brutaldev/StrongNameSigner/issues/24#issuecomment-229412636,
or mute the thread
https://github.com/notifications/unsubscribe/ADL3V4JmUrt-7q1Z-ydOjwreJhP38Kbtks5qQp4cgaJpZM4JBUuc
.

<!-- gh-comment-id:229412849 --> @stevenxi commented on GitHub (Jun 29, 2016): Have no git client here. And I'm not familiar with git. On Wed, Jun 29, 2016 at 5:32 PM, Werner van Deventer < notifications@github.com> wrote: > Please create a pull request for this change. > > — > You are receiving this because you authored the thread. > Reply to this email directly, view it on GitHub > https://github.com/brutaldev/StrongNameSigner/issues/24#issuecomment-229412636, > or mute the thread > https://github.com/notifications/unsubscribe/ADL3V4JmUrt-7q1Z-ydOjwreJhP38Kbtks5qQp4cgaJpZM4JBUuc > .
Author
Owner

@brutaldev commented on GitHub (Jun 29, 2016):

I'm sorry, but I have no idea where you expect me to put this code. It doesn't replace an existing method and I have zero proof that it makes any difference to the performance. Disk I/O against 400+ files is more than likely the problem, you should probably just isolate the files you actually want to sign rather than pointing to a giant directory.

<!-- gh-comment-id:229414014 --> @brutaldev commented on GitHub (Jun 29, 2016): I'm sorry, but I have no idea where you expect me to put this code. It doesn't replace an existing method and I have zero proof that it makes any difference to the performance. Disk I/O against 400+ files is more than likely the problem, you should probably just isolate the files you actually want to sign rather than pointing to a giant directory.
Author
Owner

@stevenxi commented on GitHub (Jun 29, 2016):

I'm not expecting you to put this code to your code base, just let you know
there's a problem and provide the solution.
Feel free leave the code without change. It works fine, just slow in some
cases.

But just let you know my change speed up the same process (400+ files) to
15 seconds, as most of them are already signed. The performance bottle neck
is when updating referencing.

On Wed, Jun 29, 2016 at 5:37 PM, Werner van Deventer <
notifications@github.com> wrote:

I'm sorry, but I have no idea where you expect me to put this code. It
doesn't replace an existing method and I have zero proof that it makes any
difference to the performance. Disk I/O against 400+ files is more than
likely the problem, you should probably just isolate the files you actually
want to sign rather than pointing to a giant directory.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/brutaldev/StrongNameSigner/issues/24#issuecomment-229414014,
or mute the thread
https://github.com/notifications/unsubscribe/ADL3V-uVq5MItamf5dG6iLa5x-5YqPX6ks5qQp8_gaJpZM4JBUuc
.

<!-- gh-comment-id:229414677 --> @stevenxi commented on GitHub (Jun 29, 2016): I'm not expecting you to put this code to your code base, just let you know there's a problem and provide the solution. Feel free leave the code without change. It works fine, just slow in some cases. But just let you know my change speed up the same process (400+ files) to 15 seconds, as most of them are already signed. The performance bottle neck is when updating referencing. On Wed, Jun 29, 2016 at 5:37 PM, Werner van Deventer < notifications@github.com> wrote: > I'm sorry, but I have no idea where you expect me to put this code. It > doesn't replace an existing method and I have zero proof that it makes any > difference to the performance. Disk I/O against 400+ files is more than > likely the problem, you should probably just isolate the files you actually > want to sign rather than pointing to a giant directory. > > — > You are receiving this because you authored the thread. > Reply to this email directly, view it on GitHub > https://github.com/brutaldev/StrongNameSigner/issues/24#issuecomment-229414014, > or mute the thread > https://github.com/notifications/unsubscribe/ADL3V-uVq5MItamf5dG6iLa5x-5YqPX6ks5qQp8_gaJpZM4JBUuc > .
Author
Owner

@brutaldev commented on GitHub (Sep 1, 2016):

Will look into large numbers of files at some point, this doesn't affect many (if any) users. As for the double check, reliability trumps performance here so leaving it as is for now.

<!-- gh-comment-id:244216875 --> @brutaldev commented on GitHub (Sep 1, 2016): Will look into large numbers of files at some point, this doesn't affect many (if any) users. As for the double check, reliability trumps performance here so leaving it as is for now.
Author
Owner

@brutaldev commented on GitHub (Sep 17, 2016):

Added definition caching which massively improves the performance when dealing with a lot of assemblies. These changes were released in v2.0.0.

<!-- gh-comment-id:247739503 --> @brutaldev commented on GitHub (Sep 17, 2016): Added definition caching which massively improves the performance when dealing with a lot of assemblies. These changes were released in [v2.0.0](https://github.com/brutaldev/StrongNameSigner/releases/tag/v2.0.0).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/StrongNameSigner#21
No description provided.