<commit_before>/*
 * JDK14Parser.java
 *
 * This file is part of TDA - Thread Dump Analysis Tool.
 *
 * TDA is free software; you can redistribute it and/or modify
 * it under the terms of the Lesser GNU General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * TDA is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Lesser GNU General Public License for more details.
 *
 * You should have received a copy of the Lesser GNU General Public License
 * along with TDA; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * $Id: JDK14Parser.java,v 1.30 2006-10-18 20:05:16 irockel Exp $
 */

package com.pironet.tda;

import com.pironet.tda.utils.HistogramTableModel;
import com.pironet.tda.utils.PrefManager;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.JOptionPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;

/**
 * Parses JDK14 Thread Dumps.
 * Needs to be closed after use (so inner stream is closed).
 *
 * @author irockel
 */
public class JDK14Parser implements DumpParser {
    private int markSize = 16384;
    private int maxCheckLines = 10;
    
    private InputStream dumpFileStream = null;
    private MutableTreeNode nextDump = null;
    private BufferedReader bis = null;
    private Map threadStore = null;
    private Pattern regexPattern = null;
    private boolean millisTimeStamp = false;
    
    private int counter = 1;
    
    private int lineCounter = 0;
    
    private boolean patternError = false;
    
    private boolean foundClassHistograms = false;
    
    /** 
     * Creates a new instance of JDK14Parser 
     */
    public JDK14Parser(InputStream dumpFileStream, Map threadStore) {
        this.dumpFileStream = dumpFileStream;
        this.threadStore = threadStore;
        this.regexPattern = regexPattern;
        this.millisTimeStamp = millisTimeStamp;
        maxCheckLines = PrefManager.get().getMaxRows();
        markSize = PrefManager.get().getStreamResetBuffer();
        millisTimeStamp = PrefManager.get().getMillisTimeStamp();
        
        if((PrefManager.get().getDateParsingRegex() != null) && !PrefManager.get().getDateParsingRegex().trim().equals("")) {
            try {
                regexPattern = Pattern.compile(PrefManager.get().getDateParsingRegex());
                patternError = false;
            } catch (PatternSyntaxException pe) {
                JOptionPane.showMessageDialog(null,
                        "Error during parsing line for timestamp regular expression!\n" +
                        "Please check regular expression in your preferences. Deactivating\n" +
                        "parsing for the rest of the file! Error Message is " + pe.getMessage() + " \n",
                        "Error during Parsing", JOptionPane.ERROR_MESSAGE);
                
                //System.out.println("Failed parsing! " + pe.getMessage());
                //pe.printStackTrace();
                patternError = true;
            }
        }        
    }
    
    /**
     * returns true if at least one more dump available, already loads it
     * (this will be returned on next call of parseNext)
     */
    public boolean hasMoreDumps() {
        nextDump = parseNext();
        return(nextDump != null);
    }
    
    /**
     * @returns true, if a class histogram was found and added during parsing.
     */
    public boolean isFoundClassHistograms() {
        return(foundClassHistograms);
    }
    
    /**
     * parse the next thread dump from the stream passed with the constructor.
     * @returns null if no more thread dumps were found.
     */
    public MutableTreeNode parseNext() {
        if (nextDump != null) {
            MutableTreeNode tmpDump = nextDump;
            nextDump = null;
            return(tmpDump);
        }
        
        DefaultMutableTreeNode threadDump = null;
        ThreadInfo overallTDI = null;
        DefaultMutableTreeNode catMonitors = null;
        DefaultMutableTreeNode catThreads = null;
        DefaultMutableTreeNode catLocking = null;
        DefaultMutableTreeNode catSleeping = null;
        DefaultMutableTreeNode catWaiting = null;
        DefaultMutableTreeNode threadInfo = null;
        
        try {
            Map threads = new HashMap();
            if(bis == null) {
                bis = new BufferedReader(new InputStreamReader(dumpFileStream));
            }
            overallTDI = new ThreadInfo("Full Thread Dump No. " + counter++, null, "");
            threadDump = new DefaultMutableTreeNode(overallTDI);
            
            catThreads = new DefaultMutableTreeNode(new Category("Threads"));
            threadDump.add(catThreads);
            
            catWaiting = new DefaultMutableTreeNode(new Category("Threads waiting for Monitors"));
            threadDump.add(catWaiting);
            
            catSleeping = new DefaultMutableTreeNode(new Category("Threads sleeping on Monitors"));
            threadDump.add(catSleeping);

            catLocking = new DefaultMutableTreeNode(new Category("Threads locking Monitors"));
            threadDump.add(catLocking);
            
            catMonitors = new DefaultMutableTreeNode(new Category("Monitors"));
            threadDump.add(catMonitors);
            
            String title = null;
            String dumpKey = null;
            StringBuffer content = null;
            StringBuffer lContent = null;
            StringBuffer sContent = null;
            StringBuffer wContent = null;
            int threadCount = 0;
            int waiting = 0;
            int locking = 0;
            int sleeping = 0;
            int deadlocks = 0;
            boolean locked = true;
            boolean finished = false;
            MonitorMap mmap = new MonitorMap();
            Stack monitorStack = new Stack();
            long startTime = 0;
            Matcher matched = null;
            
            while(bis.ready() && !finished) {
                String line = bis.readLine();
                lineCounter++;
                if(locked) {
                    if(line.contains("Full thread dump")) {
                        locked = false;
                        overallTDI.threadName += " at line " + lineCounter;
                        if(startTime != 0) {
                            startTime = 0;
                        } else if(matched != null && matched.matches()) {
                            
                            String parsedStartTime = matched.group(1);
                            if(millisTimeStamp) {
                                try {
                                    // the factor is a hack for a bug in oc4j timestamp printing (pattern timeStamp=2342342340)
                                    if(parsedStartTime.length() < 13) {
                                        startTime = Long.parseLong(parsedStartTime) * (long)Math.pow(10, 13-parsedStartTime.length());
                                    } else {
                                        startTime = Long.parseLong(parsedStartTime);
                                    }
                                } catch (NumberFormatException nfe) {
                                    startTime = 0;
                                }
                                overallTDI.threadName += " around " + new Date(startTime);
                            } else {
                                overallTDI.threadName += " around " + parsedStartTime;
                            }
                            parsedStartTime = null;
                        }
                        dumpKey = overallTDI.threadName;
                    } else if(!patternError && (regexPattern != null)) {
                        try {
                            Matcher m = regexPattern.matcher(line.trim());
                            if(m.matches()) {
                                matched = m;
                            }
                        } catch (Exception ex) {
                            JOptionPane.showMessageDialog(null,
                                    "Error during parsing line for timestamp regular expression!\n" +
                                    "Please check regular expression in your preferences. Deactivating\n" +
                                    "parsing for the rest of the file! Error Message is " + ex.getMessage() + " \n",
                                    "Error during Parsing", JOptionPane.ERROR_MESSAGE);
                            
                            //System.out.println("Failed parsing! " + ex.getMessage());
                            //ex.printStackTrace();
                            patternError = true;
                        }
                    }
                } else {
                    if(line.startsWith("\"")) {
                        if(title != null) {
                            threads.put(title, content.toString());
                            content.append("</pre></pre>");
                            createCategoryNode(catThreads, title, null, content);
                            threadCount++;
                        }
                        if(wContent != null) {
                            wContent.append("</b><hr>");
                            createCategoryNode(catWaiting, title, wContent, content);
                            wContent = null;
                            waiting++;
                        }
                        if(sContent != null) {
                            sContent.append("</b><hr>");
                            createCategoryNode(catSleeping, title, sContent, content);
                            sContent = null;
                            sleeping++;
                        }
                        if(lContent != null) {
                            lContent.append("</b><hr>");
                            createCategoryNode(catLocking, title, lContent, content);
                            lContent = null;
                            locking++;
                        }
                        while(!monitorStack.empty()) {
                            mmap.parseAndAddThread((String)monitorStack.pop(), title, content.toString());
                        }
                        
                        title = line.trim();
                        content = new StringBuffer("<pre><font size=-1>");
                        content.append(line);
                        content.append("\n");
                    } else if (line.trim().startsWith("at ")) {
                        content.append(line);
                        content.append("\n");
                    } else if (line.trim().startsWith("- waiting on")) {
                        String newLine = line.replaceAll("<", "&lt;");
                        content.append(newLine);
                        if(sContent == null) {
                            sContent = new StringBuffer("<b>");
                        }
                        sContent.append(newLine.trim());
                        monitorStack.push(line);
                        sContent.append("\n");
                        content.append("\n");
                    } else if (line.trim().startsWith("- waiting to")) {
                        String newLine = line.replaceAll("<", "&lt;");
                        content.append(newLine);
                        if(wContent == null) {
                            wContent = new StringBuffer("<b>");
                        }
                        wContent.append(newLine.trim());
                        monitorStack.push(line);
                        wContent.append("\n");
                        content.append("\n");
                    } else if (line.trim().startsWith("- locked")) {
                        String newLine = line.replaceAll("<", "&lt;");
                        content.append(newLine);
                        if(lContent == null) {
                            lContent = new StringBuffer("<b>");
                        }
                        lContent.append(newLine.trim());
                        monitorStack.push(line);
                        lContent.append("\n");
                        content.append("\n");
                    }
                    
                    // last thread reached?
                    if(line.startsWith("\"Suspend Checker Thread\"")) {
                        finished = true;
                        bis.mark(markSize);
                        if((deadlocks = checkForDeadlocks(threadDump)) == 0) {
                            // no deadlocks found, set back original position.
                            bis.reset();
                        }
                        
                        bis.mark(markSize);
                        if(!(foundClassHistograms = checkForClassHistogram(threadDump))) {
                            bis.reset();
                        }
                    }
                }
            }
            StringBuffer statData = new StringBuffer("<font size=-1><table border=0><tr><td><font size=-1>Overall Thread Count</td><td><b><font size=-1>");
            statData.append(threadCount);
            statData.append("</b></td></tr>\n\n<tr><td><font size=-1>Number of threads waiting for a monitor</td><td><b><font size=-1>");
            statData.append(waiting);
            statData.append("</b></td></tr>\n\n<tr><td><font size=-1>Number of threads locking a monitor</td><td><b><font size=-1>");
            statData.append(locking);
            statData.append("</b></td></tr>\n\n<tr><td><font size=-1>Number of threads sleeping on a monitor</td><td><b><font size=-1>");
            statData.append(sleeping);
            statData.append("</b></td></tr>\n\n<tr><td><font size=-1>Number of deadlocks</td><td><b><font size=-1>");
            statData.append(deadlocks);
            statData.append("</b></td></tr></table>");
            overallTDI.content = statData.toString();
            
            // last thread
            if(title != null) {
                createCategoryNode(catThreads, title, null, content);
            }
            if(wContent != null) {
                createCategoryNode(catLocking, title, null, wContent);
                wContent = null;
            }
            if(lContent != null) {
                createCategoryNode(catLocking, title, null, lContent);
                lContent = null;
            }
            
            // dump monitors 
            if(mmap.size() > 0) {
                dumpMonitors(catMonitors, mmap);
            }
            
            // add thread dump to passed dump store.
            if((threadCount > 0) && (dumpKey != null)) {<commit_msg>fixed thread counting, added counting infos to tree view<commit_after>/*
 * JDK14Parser.java
 *
 * This file is part of TDA - Thread Dump Analysis Tool.
 *
 * TDA is free software; you can redistribute it and/or modify
 * it under the terms of the Lesser GNU General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * TDA is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Lesser GNU General Public License for more details.
 *
 * You should have received a copy of the Lesser GNU General Public License
 * along with TDA; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * $Id: JDK14Parser.java,v 1.31 2006-11-30 15:20:33 irockel Exp $
 */

package com.pironet.tda;

import com.pironet.tda.utils.HistogramTableModel;
import com.pironet.tda.utils.PrefManager;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.JOptionPane;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;

/**
 * Parses JDK14 Thread Dumps.
 * Needs to be closed after use (so inner stream is closed).
 *
 * @author irockel
 */
public class JDK14Parser implements DumpParser {
    private int markSize = 16384;
    private int maxCheckLines = 10;
    
    private InputStream dumpFileStream = null;
    private MutableTreeNode nextDump = null;
    private BufferedReader bis = null;
    private Map threadStore = null;
    private Pattern regexPattern = null;
    private boolean millisTimeStamp = false;
    
    private int counter = 1;
    
    private int lineCounter = 0;
    
    private boolean patternError = false;
    
    private boolean foundClassHistograms = false;
    
    /** 
     * Creates a new instance of JDK14Parser 
     */
    public JDK14Parser(InputStream dumpFileStream, Map threadStore) {
        this.dumpFileStream = dumpFileStream;
        this.threadStore = threadStore;
        this.regexPattern = regexPattern;
        this.millisTimeStamp = millisTimeStamp;
        maxCheckLines = PrefManager.get().getMaxRows();
        markSize = PrefManager.get().getStreamResetBuffer();
        millisTimeStamp = PrefManager.get().getMillisTimeStamp();
        
        if((PrefManager.get().getDateParsingRegex() != null) && !PrefManager.get().getDateParsingRegex().trim().equals("")) {
            try {
                regexPattern = Pattern.compile(PrefManager.get().getDateParsingRegex());
                patternError = false;
            } catch (PatternSyntaxException pe) {
                JOptionPane.showMessageDialog(null,
                        "Error during parsing line for timestamp regular expression!\n" +
                        "Please check regular expression in your preferences. Deactivating\n" +
                        "parsing for the rest of the file! Error Message is " + pe.getMessage() + " \n",
                        "Error during Parsing", JOptionPane.ERROR_MESSAGE);
                
                //System.out.println("Failed parsing! " + pe.getMessage());
                //pe.printStackTrace();
                patternError = true;
            }
        }        
    }
    
    /**
     * returns true if at least one more dump available, already loads it
     * (this will be returned on next call of parseNext)
     */
    public boolean hasMoreDumps() {
        nextDump = parseNext();
        return(nextDump != null);
    }
    
    /**
     * @returns true, if a class histogram was found and added during parsing.
     */
    public boolean isFoundClassHistograms() {
        return(foundClassHistograms);
    }
    
    /**
     * parse the next thread dump from the stream passed with the constructor.
     * @returns null if no more thread dumps were found.
     */
    public MutableTreeNode parseNext() {
        if (nextDump != null) {
            MutableTreeNode tmpDump = nextDump;
            nextDump = null;
            return(tmpDump);
        }
        
        DefaultMutableTreeNode threadDump = null;
        ThreadInfo overallTDI = null;
        DefaultMutableTreeNode catMonitors = null;
        DefaultMutableTreeNode catThreads = null;
        DefaultMutableTreeNode catLocking = null;
        DefaultMutableTreeNode catSleeping = null;
        DefaultMutableTreeNode catWaiting = null;
        DefaultMutableTreeNode threadInfo = null;
        
        try {
            Map threads = new HashMap();
            if(bis == null) {
                bis = new BufferedReader(new InputStreamReader(dumpFileStream));
            }
            overallTDI = new ThreadInfo("Full Thread Dump No. " + counter++, null, "");
            threadDump = new DefaultMutableTreeNode(overallTDI);
            
            catThreads = new DefaultMutableTreeNode(new Category("Threads"));
            threadDump.add(catThreads);
            
            catWaiting = new DefaultMutableTreeNode(new Category("Threads waiting for Monitors"));
            threadDump.add(catWaiting);
            
            catSleeping = new DefaultMutableTreeNode(new Category("Threads sleeping on Monitors"));
            threadDump.add(catSleeping);

            catLocking = new DefaultMutableTreeNode(new Category("Threads locking Monitors"));
            threadDump.add(catLocking);
            
            catMonitors = new DefaultMutableTreeNode(new Category("Monitors"));
            threadDump.add(catMonitors);
            
            String title = null;
            String dumpKey = null;
            StringBuffer content = null;
            StringBuffer lContent = null;
            StringBuffer sContent = null;
            StringBuffer wContent = null;
            int threadCount = 0;
            int waiting = 0;
            int locking = 0;
            int sleeping = 0;
            int deadlocks = 0;
            boolean locked = true;
            boolean finished = false;
            MonitorMap mmap = new MonitorMap();
            Stack monitorStack = new Stack();
            long startTime = 0;
            Matcher matched = null;
            
            while(bis.ready() && !finished) {
                String line = bis.readLine();
                lineCounter++;
                if(locked) {
                    if(line.contains("Full thread dump")) {
                        locked = false;
                        overallTDI.threadName += " at line " + lineCounter;
                        if(startTime != 0) {
                            startTime = 0;
                        } else if(matched != null && matched.matches()) {
                            
                            String parsedStartTime = matched.group(1);
                            if(millisTimeStamp) {
                                try {
                                    // the factor is a hack for a bug in oc4j timestamp printing (pattern timeStamp=2342342340)
                                    if(parsedStartTime.length() < 13) {
                                        startTime = Long.parseLong(parsedStartTime) * (long)Math.pow(10, 13-parsedStartTime.length());
                                    } else {
                                        startTime = Long.parseLong(parsedStartTime);
                                    }
                                } catch (NumberFormatException nfe) {
                                    startTime = 0;
                                }
                                overallTDI.threadName += " around " + new Date(startTime);
                            } else {
                                overallTDI.threadName += " around " + parsedStartTime;
                            }
                            parsedStartTime = null;
                        }
                        dumpKey = overallTDI.threadName;
                    } else if(!patternError && (regexPattern != null)) {
                        try {
                            Matcher m = regexPattern.matcher(line.trim());
                            if(m.matches()) {
                                matched = m;
                            }
                        } catch (Exception ex) {
                            JOptionPane.showMessageDialog(null,
                                    "Error during parsing line for timestamp regular expression!\n" +
                                    "Please check regular expression in your preferences. Deactivating\n" +
                                    "parsing for the rest of the file! Error Message is " + ex.getMessage() + " \n",
                                    "Error during Parsing", JOptionPane.ERROR_MESSAGE);
                            
                            //System.out.println("Failed parsing! " + ex.getMessage());
                            //ex.printStackTrace();
                            patternError = true;
                        }
                    }
                } else {
                    if(line.startsWith("\"")) {
                        if(title != null) {
                            threads.put(title, content.toString());
                            content.append("</pre></pre>");
                            createCategoryNode(catThreads, title, null, content);
                            threadCount++;
                        }
                        if(wContent != null) {
                            wContent.append("</b><hr>");
                            createCategoryNode(catWaiting, title, wContent, content);
                            wContent = null;
                            waiting++;
                        }
                        if(sContent != null) {
                            sContent.append("</b><hr>");
                            createCategoryNode(catSleeping, title, sContent, content);
                            sContent = null;
                            sleeping++;
                        }
                        if(lContent != null) {
                            lContent.append("</b><hr>");
                            createCategoryNode(catLocking, title, lContent, content);
                            lContent = null;
                            locking++;
                        }
                        while(!monitorStack.empty()) {
                            mmap.parseAndAddThread((String)monitorStack.pop(), title, content.toString());
                        }
                        
                        title = line.trim();
                        content = new StringBuffer("<pre><font size=-1>");
                        content.append(line);
                        content.append("\n");
                    } else if (line.trim().startsWith("at ")) {
                        content.append(line);
                        content.append("\n");
                    } else if (line.trim().startsWith("- waiting on")) {
                        String newLine = line.replaceAll("<", "&lt;");
                        content.append(newLine);
                        if(sContent == null) {
                            sContent = new StringBuffer("<b>");
                        }
                        sContent.append(newLine.trim());
                        monitorStack.push(line);
                        sContent.append("\n");
                        content.append("\n");
                    } else if (line.trim().startsWith("- waiting to")) {
                        String newLine = line.replaceAll("<", "&lt;");
                        content.append(newLine);
                        if(wContent == null) {
                            wContent = new StringBuffer("<b>");
                        }
                        wContent.append(newLine.trim());
                        monitorStack.push(line);
                        wContent.append("\n");
                        content.append("\n");
                    } else if (line.trim().startsWith("- locked")) {
                        String newLine = line.replaceAll("<", "&lt;");
                        content.append(newLine);
                        if(lContent == null) {
                            lContent = new StringBuffer("<b>");
                        }
                        lContent.append(newLine.trim());
                        monitorStack.push(line);
                        lContent.append("\n");
                        content.append("\n");
                    }
                    
                    // last thread reached?
                    if(line.startsWith("\"Suspend Checker Thread\"")) {
                        finished = true;
                        bis.mark(markSize);
                        if((deadlocks = checkForDeadlocks(threadDump)) == 0) {
                            // no deadlocks found, set back original position.
                            bis.reset();
                        }
                        
                        bis.mark(markSize);
                        if(!(foundClassHistograms = checkForClassHistogram(threadDump))) {
                            bis.reset();
                        }
                    }
                }
            }
            // last thread
            if(title != null) {
                threads.put(title, content.toString());
                content.append("</pre></pre>");
                createCategoryNode(catThreads, title, null, content);
                threadCount++;
            }
            if(wContent != null) {
                wContent.append("</b><hr>");
                createCategoryNode(catWaiting, title, null, wContent);
                wContent = null;
                waiting++;
            }
            if(sContent != null) {
                sContent.append("</b><hr>");
                createCategoryNode(catSleeping, title, sContent, content);
                sContent = null;
                sleeping++;
            }
            if(lContent != null) {
                sContent.append("</b><hr>");
                createCategoryNode(catLocking, title, null, lContent);
                lContent = null;
                locking++;
            }
            
            StringBuffer statData = new StringBuffer("<font size=-1><table border=0><tr><td><font size=-1>Overall Thread Count</td><td><b><font size=-1>");
            statData.append(threadCount);
            statData.append("</b></td></tr>\n\n<tr><td><font size=-1>Number of threads waiting for a monitor</td><td><b><font size=-1>");
            statData.append(waiting);
            statData.append("</b></td></tr>\n\n<tr><td><font size=-1>Number of threads locking a monitor</td><td><b><font size=-1>");
            statData.append(locking);
            statData.append("</b></td></tr>\n\n<tr><td><font size=-1>Number of threads sleeping on a monitor</td><td><b><font size=-1>");
            statData.append(sleeping);
            statData.append("</b></td></tr>\n\n<tr><td><font size=-1>Number of deadlocks</td><td><b><font size=-1>");
            statData.append(deadlocks);
            statData.append("</b></td></tr></table>");
            overallTDI.content = statData.toString();
            
            ((Category) catThreads.getUserObject()).setName(((Category) catThreads.getUserObject()) + " (" + threadCount + " Threads overall)");
            ((Category) catWaiting.getUserObject()).setName(((Category) catWaiting.getUserObject()) + " (" + waiting + " Threads waiting)");
            ((Category) catSleeping.getUserObject()).setName(((Category) catSleeping.getUserObject()) + " (" + sleeping + " Threads sleeping)");
            ((Category) catLocking.getUserObject()).setName(((Category) catLocking.getUserObject()) + " (" + locking + " Threads locking)");
            
            
            // dump monitors 
            if(mmap.size() > 0) {
                dumpMonitors(catMonitors, mmap);
            }
            
            // add thread dump to passed dump store.
            if((threadCount > 0) && (dumpKey != null)) {
{'fraction_non_alphanumeric': 0.10146699266503667, 'fraction_numerical': 0.005893047457839634, 'mean_word_length': 1.381531800537474, 'pattern_counts': {'":': 0, '<': 151, '<?xml version=': 0, '>': 147, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5822296', 'n_tokens_mistral': 7843, 'n_tokens_neox': 7439, 'n_words': 1814}