Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

threads.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2001, John Lambert jlambert@jlambert.com
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without modification, are 
00006 permitted provided that the following conditions are met:
00007 
00008 Redistributions of source code must retain the above copyright notice, this list of 
00009 conditions and the following disclaimer.
00010 
00011 Redistributions in binary form must reproduce the above copyright notice, this list
00012 of conditions and the following disclaimer in the documentation and/or other
00013 materials provided with the distribution. 
00014 
00015 Neither the name of the xdProf project nor the names of its contributors may be used
00016 to endorse or promote products derived from this software without specific prior 
00017 written permission. 
00018 
00019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
00020 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00021 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00022 SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
00023 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00024 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
00025 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
00026 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
00027 WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028 */
00029 /*
00030 $Header: /xdprof-dll/threads.cpp 40    5/09/01 5:29a Admin $ 
00031  */
00032 #include "xdprof.h"
00033 
00034 
00036 bool HotSpot = false;
00037 
00039 static char* const NullCharPointer = "null";
00040 
00045 static inline char* FixNull(char* c)
00046 {
00047     return (c == null) ? NullCharPointer : c;
00048 }
00049 
00050 
00051 ThreadInfo::ThreadInfo(char *thread_name, char *group_name, char *parent_name, jobjectID thread_id, JNIEnv *thread_env_id)
00052 :   m_thread_name(FixNull(thread_name)), 
00053     m_thread_id(thread_id),
00054     m_thread_env_id(*thread_env_id),
00055     m_started(0)
00056 {
00057     _snprintf(m_printable, 512, "%s\n%s\n%s\n", FixNull(thread_name), FixNull(group_name), FixNull(parent_name));
00058 }
00059 
00060 ThreadInfo::ThreadInfo(const ThreadInfo & ci)
00061 {
00062     strncpy(m_printable, ci.m_printable, 512);
00063     m_thread_name = ci.m_thread_name;
00064 }
00065 
00066 void ThreadInfo::setStarted(unsigned long started) const
00067 {
00068     m_started = started;
00069 }
00070 
00071 inline unsigned long ThreadInfo::getStarted() const
00072 {
00073     return m_started;
00074 }
00075 
00076 inline const char* ThreadInfo::getShortInfo() const
00077 {
00078     return m_printable;
00079 }
00080 
00081 string ThreadInfo::getThreadName() const
00082 {
00083     return m_thread_name;
00084 }
00085 
00086 
00087 ClassInfo::ClassInfo(const ClassInfo & ci)
00088 {
00089     m_class_name = ci.m_class_name;
00090     m_source_name = ci.m_source_name;
00091     m_class_id = ci.m_class_id;
00092 
00093     if (ci.m_printable == null)
00094     {
00095         m_printable = null;
00096     }
00097     else
00098     {
00099         m_printable = new char[512];
00100         strncpy(m_printable, ci.m_printable, 512);
00101     }
00102 }
00103 
00104 ClassInfo::~ClassInfo()
00105 {
00106     delete[] m_printable ;  // works even if m_printable is null
00107 }
00108 
00109 ClassInfo::ClassInfo(  char * class_name,  char * source_name, jclassID class_id)
00110 {
00111     if (!HotSpot)
00112     {
00113         m_class_name = class_name;
00114         m_source_name = source_name;
00115     }
00116     else
00117     {
00118 
00119         m_class_name = new char[512];
00120         strncpy(m_class_name, class_name, 512);
00121         
00122         if (source_name != null)
00123         {
00124             m_source_name = new char[512];
00125             strncpy(m_source_name, source_name, 512);
00126         }
00127         else
00128             m_source_name = null;
00129 
00130     }
00131     m_class_id = class_id;
00132     m_printable = null;
00133 }
00134 
00135 const char * ClassInfo::getShortInfo() const
00136 {
00137     if (m_printable != null)
00138         return m_printable;
00139     m_printable = new char[512];
00140     _snprintf(m_printable, 512, "%08X %s %s", m_class_id, m_class_name, (m_source_name == null) ? "unknown" : m_source_name);
00141     return m_printable;
00142 }
00143 
00144 MethodInfo::MethodInfo(const MethodInfo & mi)
00145 {
00146     m_class_id = mi.m_class_id;
00147     m_method_id = mi.m_method_id;
00148     m_method_name = mi.m_method_name;
00149     m_method_signature = mi.m_method_signature;
00150     m_short_string = null;
00151 }
00152 
00153 MethodInfo::~MethodInfo()
00154 {
00155     cout << "~MI " << m_method_id << endl;
00156     delete[] m_short_string;
00157 }
00158 
00159 
00160 // classid methodid methodname methodsig
00161 inline const char* MethodInfo::getShortInfo() const
00162 {
00163     if (m_short_string != null)
00164         return m_short_string;
00165     
00166     m_short_string = new char[512];
00167     _snprintf(m_short_string, 512, "%08X %08X %s %s\0", m_class_id, m_method_id, m_method_name, m_method_signature);
00168     return m_short_string;
00169 }
00170 jobjectID MethodInfo::getClassID() const
00171 {
00172     return m_class_id;
00173 }
00174 
00175 MethodInfo::MethodInfo(
00176      char * method_name,
00177      char * method_signature,
00178     jint /* start_lineno */,
00179     jint /* end_lineno */,
00180     jmethodID method_id,
00181     jobjectID class_id)
00182 {
00183     m_class_id = class_id;
00184     m_method_id = method_id;
00185     m_short_string = null;
00186 
00187     if (!HotSpot)
00188     {
00189         m_method_name = method_name;
00190         m_method_signature = method_signature; 
00191     }
00192     else
00193     {
00194         m_method_name = new char[512];
00195         m_method_signature = new char[512];
00196         strncpy(m_method_name, method_name, 512);
00197         strncpy(m_method_signature, method_signature , 512);
00198     }
00199     
00200     //printf("%s\n",m_short_string);
00201 }
00202 
00203 
00204 
00205 void ThreadDump(const string& info, ThreadID caller)
00206 {
00207     ostringstream output;
00208 
00209     Lock(threads_lock);
00210     Lock(methods_lock);
00211     Lock(output_lock);
00212 
00213     if (ShutdownRequested)
00214     {
00215     unsafe_debug("shutdown in ", "ThreadDump");
00216     Unlock(output_lock);
00217     Unlock(methods_lock);
00218     Unlock(threads_lock);
00219     return;
00220 
00221     }
00222 
00223 //if(false)
00224     CALL(DisableGC());
00225     
00226     ThreadMap::iterator t;
00227     set<ThreadID> SuspendedThreads;
00228 
00229     const char Endl = '\n';
00230 
00231     // suspend all threads
00232     for (t = Threads.begin(); t != Threads.end(); ++t)
00233     {
00234         ThreadID tid = t->first;
00235         jlong status = CALL(GetThreadStatus)(tid);
00236         if ((tid != caller) &&
00237             (
00238             ((status & (~JVMPI_THREAD_INTERRUPTED)) == JVMPI_THREAD_RUNNABLE) 
00239             ||      HotSpot
00240             )
00241             )
00242         {
00243             CALL(SuspendThread)(tid);   
00244             SuspendedThreads.insert(tid);
00245             unsafe_debug("Suspended ", tid);
00246         }
00247         else
00248         {
00249             unsafe_debug(tid, (long)status);
00250         }
00251     }
00252 
00253     unsafe_debug("#threads ", Threads.size());
00254     output << "// start_message; num threads: " << Threads.size() << Endl;
00255     output << Threads.size() << Endl;
00256     const int number_of_frames = 100;
00257 
00258     MethodSet methods_to_send;
00259     JVMPI_CallTrace trace;
00260     JVMPI_CallFrame tframes[number_of_frames];
00261     const JVMPI_CallFrame* f;
00262     for (t = Threads.begin(); t != Threads.end(); ++t)
00263     {
00264         const ThreadInfo& ti = t->second;
00265 
00266         output << "// start_thread " << t->first  << Endl;
00267         output << t->first << Endl; // threadid
00268     
00269         jint thread_status = CALL(GetThreadStatus)(t->first);
00270         output << ti.getShortInfo();
00271         output << ti.getStarted() << Endl;
00272         output << thread_status << Endl;    // thread status
00273 
00274 //      unsafe_debug(t->first, ti.getThreadName(), thread_status);
00275         
00276         trace.frames = tframes;
00277         trace.env_id = t->first;
00278 //assert(false);        
00279         CALL(GetCallTrace)(&trace, number_of_frames);
00280 
00281         unsafe_debug("num frames: ", trace.num_frames);
00282 
00283         output << "// num frames = " << trace.num_frames << Endl;
00284         output << trace.num_frames << Endl;
00285         
00286         // send each frame
00287         for (int i = 0; i < trace.num_frames; i++)
00288         {
00289             //output << "// start frame " << i << Endl;
00290             f = &trace.frames[i];
00291             
00292             output << f->method_id << ' ' << f->lineno << Endl; // send method_id lineno
00293             
00294             methods_to_send.insert(f->method_id);
00295         }
00296 
00297     }
00298 
00299     output << "// sending methods now, count=" << methods_to_send.size() << Endl;
00300     output << methods_to_send.size() << Endl;
00301     ClassSet classes_to_send;
00302     
00303     const MethodInfo * the_method;
00304     //const MethodMap::iterator
00305     MethodMap::iterator m;
00306     const MethodMap::iterator m_end = Methods.end();
00307     MethodMap::iterator mc_end = MethodCache.end(); // look in the cache
00308     const MethodSet::iterator mse =  methods_to_send.end();
00309     for(MethodSet::iterator mi = methods_to_send.begin(); mi != mse; ++mi)
00310     {
00311 
00312         m = MethodCache.find(*mi);
00313         if (m == mc_end)
00314         {
00315             // couldn't find, so load it and cache it
00316             m = Methods.find(*mi);
00317             
00318             //assert(m != Methods.end());
00319             if (m == m_end )
00320             {
00321                 jclassID cid = CALL(GetMethodClass(*mi));
00322                 unsafe_debug("Couldn't find ", *mi, cid);
00323                 unsafe_debug("perf Methods = ", Methods.size());
00324                 output << ends;
00325 //              unsafe_debug("output:: ", output.str());
00326                 
00327                 assert(m != Methods.end());
00328                 CALL(EnableGC());
00329                 Unlock(output_lock);
00330                 Unlock(methods_lock);
00331                 Unlock(threads_lock);
00332                 return;
00333             }       
00334                         
00335             MethodCache.insert(make_pair(*mi, m->second));
00336             mc_end = MethodCache.end();
00337         }
00338         //m = Methods.find(*mi);    //TODO: caching?
00339         assert(m != Methods.end());
00340         the_method = m->second;
00341 
00342         //classid methodid methodname methodsig
00343         output << the_method->getShortInfo() << Endl;
00344         unsafe_debug(the_method->getClassID(), the_method->getShortInfo());
00345         classes_to_send.insert(the_method->getClassID());
00346     }
00347 
00348     output << "// sending classes now, count=" << classes_to_send.size() << Endl;
00349     output << classes_to_send.size() << Endl;
00350     const ClassInfoMap::iterator end = ClassCache.end();
00351     ClassInfoMap::iterator c;
00352     const ClassSet::iterator cse = classes_to_send.end();
00353     for (ClassSet::iterator ci = classes_to_send.begin(); ci != cse; ++ci)
00354     {
00355         c = ClassCache.find(*ci);
00356         if (c == end)
00357         {
00358             c = Classes.find(*ci);
00359             ClassCache.insert(make_pair(*ci, c->second));
00360         }
00361         //c = Classes.find(*ci);    //TODO: caching?
00362         assert(c != Classes.end());
00363         // class_id class_name source_name
00364         //unsafe_debug("ci1", c->second.getShortInfo() );
00365         output << c->second.getShortInfo() << Endl;
00366     }
00367 
00368 
00369     output << "// end_message" << Endl;
00370     output << ends;
00371 
00372     // Restart all suspended threads; in reverse order.
00373     set<ThreadID>::reverse_iterator susIter;
00374     const set<ThreadID>::reverse_iterator stre = SuspendedThreads.rend();
00375     for (susIter = SuspendedThreads.rbegin(); susIter != stre; ++susIter)
00376     {
00377         CALL(ResumeThread(*susIter));
00378         unsafe_debug("Resumed", *susIter);
00379     }
00380 
00381 //if(false)
00382     CALL(EnableGC());
00383     Unlock(output_lock);
00384     Unlock(methods_lock);
00385     Unlock(threads_lock);
00386     //return;
00387     Lock(output_lock);
00388     const int chunk = 1024;
00389     const string s = output.str();
00390     const char* cp = s.c_str();
00391     // send in tiny chunks
00392 
00393 RecordPacket(info.size() + s.size());
00394 
00395     Send(info);
00396 
00397     for (string::size_type p = 0; p < (s.size()/chunk); p++)
00398     {
00399         Send(cp, chunk);
00400         cp += chunk;
00401     }
00402     Send(cp, strlen(cp));
00403     Unlock(output_lock);
00404     
00405     LeaveRelease;
00406     unsafe_debug("perf ", "");
00407     unsafe_debug("perf classes to send count", classes_to_send.size());
00408     unsafe_debug("perf Classes", Classes.size());
00409     unsafe_debug("perf ClassesCache", ClassCache.size());
00410     unsafe_debug("perf methods to send count", methods_to_send.size());
00411     unsafe_debug("perf MethodsCache = ", MethodCache.size());
00412     unsafe_debug("perf Methods = ", Methods.size());
00413 
00414 
00415     
00416     ofstream outtrace("network.txt");
00417     outtrace << info <<  s << endl;
00418 
00419     debug("message", s.size());
00420     debug(s);
00421 
00422 }
00423 
00424 

Generated at Sun Jun 24 20:57:16 2001 for xdprof by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001