source: trunk/CrypPlugins/QuadraticSieve/QuadraticSieve.cs @ 1676

Last change on this file since 1676 was 1676, checked in by Sven Rech, 12 years ago

quadratic sieve:

o altered the alive checking mechanism once again
o fixed msieve bug when pressing stop button

File size: 35.2 KB
Line 
1/*                             
2   Copyright 2009 Team CrypTool (Sven Rech,Dennis Nolte,Raoul Falk,Nils Kopal), Uni Duisburg-Essen
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17using System;
18using System.Collections;
19using System.Linq;
20using System.Text;
21using Cryptool.PluginBase;
22using Cryptool.PluginBase.IO;
23using Cryptool.PluginBase.Miscellaneous;
24using System.ComponentModel;
25using System.Threading;
26using System.IO;
27using System.Windows.Controls;
28using System.Windows.Threading;
29using System.Windows;
30using System.Reflection;
31using System.Numerics;
32using System.Collections.Generic;
33using System.Diagnostics;
34using Cryptool.P2P;
35
36namespace Cryptool.Plugins.QuadraticSieve
37{
38    /// <summary>
39    /// This class wraps the msieve algorithm in version 1.42 which you can find at http://www.boo.net/~jasonp/qs.html
40    /// It also extends the msieve functionality to multi threading
41    /// Many thanks to the author of msieve "jasonp_sf"
42    ///
43    /// For further information on quadratic sieve or msieve please have a look at the above mentioned URL
44    /// </summary>
45    [Author("Sven Rech", "rech@cryptool.org", "Uni Duisburg-Essen", "http://www.uni-due.de")]
46    [PluginInfo(false, "Quadratic Sieve", "Sieving Primes", "QuadraticSieve/DetailedDescription/Description.xaml", "QuadraticSieve/iconqs.png")]
47    class QuadraticSieve : DependencyObject, IThroughput
48    {
49        #region private variables
50
51        private readonly string directoryName;
52        private QuadraticSieveSettings settings;
53        private BigInteger inputNumber;
54        private BigInteger[] outputFactors;
55        private bool running;
56        private Queue yieldqueue;
57        private AutoResetEvent yieldEvent = new AutoResetEvent(false);
58        private IntPtr obj = IntPtr.Zero;
59        private volatile int threadcount = 0;
60        private ArrayList conf_list;
61        private Mutex conf_listMutex = new Mutex();
62        private bool userStopped = false;
63        private FactorManager factorManager;
64        private PeerToPeer peerToPeer;
65        private bool usePeer2Peer;
66        private bool useGnuplot = false;
67        private StreamWriter gnuplotFile;
68        private double[] relationsPerMS;
69
70        private static Assembly msieveDLL = null;
71        private static Type msieve = null;
72        private static bool alreadyInUse = false;
73        private static Mutex alreadyInUseMutex = new Mutex();
74
75        #endregion
76
77        #region events
78
79        public event StatusChangedEventHandler OnPluginStatusChanged;
80        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
81        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
82        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
83        public event PluginProgressChangedEventHandler OnPluginProcessChanged;
84
85        #endregion
86
87        #region public
88
89        /// <summary>
90        /// Constructor
91        ///
92        /// constructs a new QuadraticSieve plugin
93        /// </summary>
94        public QuadraticSieve()
95        {
96            Settings = new QuadraticSieveSettings();
97
98            directoryName = Path.Combine(DirectoryHelper.DirectoryLocalTemp, "msieve");
99            if (!Directory.Exists(directoryName)) Directory.CreateDirectory(directoryName);
100
101            QuickWatchPresentation = new QuadraticSievePresentation();
102
103            peerToPeer = new PeerToPeer(quadraticSieveQuickWatchPresentation, yieldEvent);
104            peerToPeer.P2PWarning += new PeerToPeer.P2PWarningHandler(peerToPeer_P2PWarning);
105           
106            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
107            {
108                quadraticSieveQuickWatchPresentation.peer2peer.Visibility = settings.UsePeer2Peer ? Visibility.Visible : Visibility.Collapsed;
109                quadraticSieveQuickWatchPresentation.Redraw();
110                quadraticSieveQuickWatchPresentation.timeLeft.Text = "?";
111                quadraticSieveQuickWatchPresentation.endTime.Text = "?";
112                quadraticSieveQuickWatchPresentation.logging.Text = "Currently not sieving.";
113            }
114            , null);
115        }
116
117        /// <summary>
118        /// Getter / Setter for the settings of this plugin
119        /// </summary>
120        public Cryptool.PluginBase.ISettings Settings
121        {
122            get { return this.settings; }
123            set
124            {
125                this.settings = (QuadraticSieveSettings)value;
126                this.settings.PropertyChanged += new PropertyChangedEventHandler(settings_PropertyChanged);
127            }
128        }
129
130        private void settings_PropertyChanged(object sender, PropertyChangedEventArgs e)
131        {
132            if (e.PropertyName == "UsePeer2Peer")
133            {
134                if (quadraticSieveQuickWatchPresentation != null)
135                {
136                    quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
137                    {
138                        quadraticSieveQuickWatchPresentation.peer2peer.Visibility = settings.UsePeer2Peer ? Visibility.Visible : Visibility.Collapsed;
139                        quadraticSieveQuickWatchPresentation.Redraw();
140                    }, null);
141                }
142            }
143        }
144
145        /// <summary>
146        /// Called by the environment before executing this plugin
147        /// </summary>
148        public void PreExecution()
149        { 
150        }
151       
152        /// <summary>
153        /// Called by the environment to execute this plugin
154        /// </summary>
155        public void Execute()
156        {
157            if (checkInUse())
158                return;
159            try
160            {
161                usePeer2Peer = settings.UsePeer2Peer;
162                if (usePeer2Peer && !P2PManager.IsConnected)
163                {
164                    GuiLogMessage("No connection to Peer2Peer network. Sieving locally now!", NotificationLevel.Warning);
165                    usePeer2Peer = false;
166                }
167                if (usePeer2Peer && settings.Channel.Trim() == "")
168                {
169                    GuiLogMessage("No channel for Peer2Peer network specified. Sieving locally now!", NotificationLevel.Warning);
170                    usePeer2Peer = false;
171                }
172                if (usePeer2Peer)
173                {
174                    peerToPeer.SetChannel(settings.Channel);
175                    peerToPeer.SetNumber(InputNumber);
176                }
177
178                if (useGnuplot)
179                    gnuplotFile = new StreamWriter(Path.Combine(directoryName, "gnuplot.dat"), false);
180
181                userStopped = false;
182
183                if (InputNumber != 0)
184                {
185                    if (InputNumber.ToString().Length >= 275)
186                    {
187                        GuiLogMessage("Input too big.", NotificationLevel.Error);
188                        return;
189                    }
190
191                    String timeLeft_message = "?";
192                    String endtime_message = "?";
193                    String logging_message = "Starting quadratic sieve, please wait!";
194
195                    GuiLogMessage(logging_message, NotificationLevel.Info);
196                    quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
197                    {
198                        quadraticSieveQuickWatchPresentation.ProgressYields.Clear();
199                        quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
200                        quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
201                        quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
202                        quadraticSieveQuickWatchPresentation.factorList.Items.Clear();
203                        quadraticSieveQuickWatchPresentation.factorInfo.Content = "Searching trivial factors!";
204                        if (usePeer2Peer)
205                            quadraticSieveQuickWatchPresentation.relationsInfo.Content = "";
206                        else
207                            quadraticSieveQuickWatchPresentation.relationsInfo.Content = "Only local sieving!";
208                    }
209                    , null);
210
211                    DateTime start_time = DateTime.Now;
212
213                    initMsieveDLL();
214                    factorManager = new FactorManager(msieve.GetMethod("getPrimeFactors"), msieve.GetMethod("getCompositeFactors"), InputNumber);
215                    factorManager.FactorsChanged += this.FactorsChanged;
216
217                    //Now factorize:               
218                    try
219                    {
220                        string file = Path.Combine(directoryName, "" + InputNumber + ".dat");
221                        if (settings.DeleteCache && File.Exists(file))
222                            File.Delete(file);
223                        MethodInfo start = msieve.GetMethod("start");
224                        start.Invoke(null, new object[] { InputNumber.ToString(), file });
225                        obj = IntPtr.Zero;
226                    }
227                    catch (Exception ex)
228                    {
229                        GuiLogMessage("Error using msieve. " + ex.Message, NotificationLevel.Error);
230                        stopThreads();
231                        return;
232                    }
233
234                    if (!userStopped)
235                    {
236                        timeLeft_message = "0 seconds left";
237                        endtime_message = "" + (DateTime.Now);
238                        logging_message = "Sieving finished in " + (DateTime.Now - start_time) + "!";
239
240                        GuiLogMessage(logging_message, NotificationLevel.Info);
241                        quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
242                        {
243                            quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
244                            quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
245                            quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
246                            quadraticSieveQuickWatchPresentation.factorInfo.Content = "";
247                        }
248                        , null);
249
250                        Debug.Assert(factorManager.CalculateNumber() == InputNumber);
251                        OutputFactors = factorManager.getPrimeFactors();
252                    }
253                    else
254                    {
255                        timeLeft_message = "0 sec left";
256                        endtime_message = "Stopped";
257                        logging_message = "Stopped by user!";
258
259                        GuiLogMessage(logging_message, NotificationLevel.Info);
260                        quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
261                        {
262                            quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
263                            quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
264                            quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
265                            quadraticSieveQuickWatchPresentation.factorInfo.Content = "";
266                        }
267                        , null);
268                    }
269
270                    ProgressChanged(1, 1);
271
272                }
273                if (useGnuplot)
274                    gnuplotFile.Close();
275            }
276            finally
277            {
278                alreadyInUse = false;
279            }
280        }
281
282        private bool checkInUse()
283        {
284            try
285            {
286                alreadyInUseMutex.WaitOne();
287                if (alreadyInUse)
288                {
289                    GuiLogMessage("QuadraticSieve plugin is only allowed to execute ones at a time due to technical restrictions.", NotificationLevel.Error);
290                    return true;
291                }
292                else
293                {
294                    alreadyInUse = true;
295                    return false;
296                }
297            }
298            finally
299            {
300                alreadyInUseMutex.ReleaseMutex();
301            }
302        }
303       
304        /// <summary>
305        /// Called by the environment after execution
306        /// </summary>
307        public void PostExecution()
308        {
309        }
310
311        /// <summary>
312        /// Called by the environment to pause execution
313        /// </summary>
314        public void Pause()
315        {
316        }
317
318        /// <summary>
319        /// Called by the environment to stop execution
320        /// </summary>
321        public void Stop()
322        {
323            this.userStopped = true;
324            if (obj != IntPtr.Zero)
325            {
326                stopThreads();
327                MethodInfo stop = msieve.GetMethod("stop");
328                stop.Invoke(null, new object[] { obj });
329            }
330
331        }
332
333        /// <summary>
334        /// Called by the environment to initialize this plugin
335        /// </summary>
336        public void Initialize()
337        {
338            settings.Initialize();
339        }
340
341        /// <summary>
342        /// Called by the environment to dispose this plugin
343        /// </summary>
344        public void Dispose()
345        {
346        }
347
348        /// <summary>
349        /// Getter / Setter for the input number which should be factorized
350        /// </summary>
351        [PropertyInfo(Direction.InputData, "Number input", "Enter the number you want to factorize", "", DisplayLevel.Beginner)]
352        public BigInteger InputNumber
353        {
354            get
355            {
356                return inputNumber;
357            }
358            set
359            {
360                this.inputNumber = value;
361                OnPropertyChanged("InputNumber");
362            }
363        }
364
365        /// <summary>
366        /// Getter / Setter for the factors calculated by msieve
367        /// </summary>
368        [PropertyInfo(Direction.OutputData, "Factors output", "Your factors will be sent here", "", DisplayLevel.Beginner)]
369        public BigInteger[] OutputFactors
370        {
371            get
372            {
373                return outputFactors;
374            }
375            set
376            {
377                this.outputFactors = value;
378                OnPropertyChanged("OutputFactors");
379            }
380        }
381       
382        /// <summary>
383        /// Called when a property of this plugin changes
384        /// </summary>
385        /// <param name="name">name</param>
386        public void OnPropertyChanged(string name)
387        {
388            EventsHelper.PropertyChanged(PropertyChanged, this, new PropertyChangedEventArgs(name));
389        }
390
391        /// <summary>
392        /// Getter / Setter for the presentation of this plugin
393        /// </summary>
394        public UserControl Presentation { get; private set; }
395
396        /// <summary>
397        /// Getter / Setter for the QuickWatchPresentation of this plugin
398        /// </summary>
399        public UserControl QuickWatchPresentation
400        {
401            get;
402            private set;
403        }
404
405        #endregion
406
407        #region private
408
409        /// <summary>
410        /// calculate a String which shows the timespan
411        ///
412        /// example
413        ///
414        ///     4 days
415        /// or
416        ///     2 minutes
417        /// </summary>
418        /// <param name="ts"></param>
419        /// <returns></returns>
420        private String showTimeSpan(TimeSpan ts)
421        {
422            String res = "";
423            if (ts.Days != 0)
424                res = ts.Days + " days ";
425            if (ts.Hours != 0 || res.Length != 0)
426                res += ts.Hours + " hours ";
427            if (ts.Minutes != 0)
428                res += ts.Minutes + " minutes";
429            if (res.Length == 0)
430                res += ts.Seconds + " seconds";
431            return res;
432        }
433
434        /// <summary>
435        /// Callback method to prepare sieving
436        /// Called by msieve
437        ///
438        /// </summary>
439        /// <param name="conf">pointer to configuration</param>
440        /// <param name="update">number of relations found</param>
441        /// <param name="core_sieve_fcn">pointer to internal sieve function of msieve</param>
442        private void prepareSieving(IntPtr conf, int update, IntPtr core_sieve_fcn, int max_relations)
443        {
444            int threads = Math.Min(settings.CoresUsed, Environment.ProcessorCount-1);
445            MethodInfo getObjFromConf = msieve.GetMethod("getObjFromConf");
446            this.obj = (IntPtr)getObjFromConf.Invoke(null, new object[] { conf });           
447            yieldqueue = Queue.Synchronized(new Queue());
448            conf_list = new ArrayList();
449
450            String message = "Start sieving using " + (threads + 1) + " cores!";
451            GuiLogMessage(message, NotificationLevel.Info);
452            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
453            {
454                quadraticSieveQuickWatchPresentation.logging.Text = message;
455                if (usePeer2Peer)
456                    quadraticSieveQuickWatchPresentation.relationsInfo.Content = "";
457            }
458            , null);         
459
460            ProgressChanged(0.1, 1.0);
461
462            running = true;
463            //start helper threads:
464            relationsPerMS = new double[threads + 1];
465            for (int i = 0; i < threads+1; i++)
466            {
467                MethodInfo cloneSieveConf = msieve.GetMethod("cloneSieveConf");
468                IntPtr clone = (IntPtr)cloneSieveConf.Invoke(null, new object[] { conf });               
469                conf_list.Add(clone);
470                WaitCallback worker = new WaitCallback(MSieveJob);
471                ThreadPool.QueueUserWorkItem(worker, new object[] { clone, update, core_sieve_fcn, yieldqueue, i });
472            }
473
474            //manage the yields of the other threads:
475            manageYields(conf, max_relations);  //this method returns as soon as there are enough relations found
476            if (userStopped)
477                return;
478
479            //sieving is finished now, so give some informations and stop threads:
480            ProgressChanged(0.9, 1.0);
481            GuiLogMessage("Sieving finished", NotificationLevel.Info);
482            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
483            {
484                quadraticSieveQuickWatchPresentation.timeLeft.Text = "";
485                quadraticSieveQuickWatchPresentation.endTime.Text = "";
486                quadraticSieveQuickWatchPresentation.factorInfo.Content = "Found enough relations! Please wait...";
487            }, null);
488           
489            stopThreads();
490            if (yieldqueue != null)
491                yieldqueue.Clear();
492        }
493
494        /// <summary>
495        /// Manages the whole yields that are created during the sieving process by the other threads (and other peers).
496        /// Returns true, if enough relations have been found.
497        /// </summary>
498        private void manageYields(IntPtr conf, int max_relations)
499        {
500            MethodInfo serializeYield = msieve.GetMethod("serializeYield");
501            MethodInfo deserializeYield = msieve.GetMethod("deserializeYield");
502            MethodInfo getNumRelations = msieve.GetMethod("getNumRelations");
503            int num_relations = (int)getNumRelations.Invoke(null, new object[] { conf });
504            int start_relations = num_relations;
505            DateTime start_sieving_time = DateTime.Now;
506            MethodInfo saveYield = msieve.GetMethod("saveYield");
507
508            while (num_relations < max_relations)
509            {
510                ProgressChanged((double)num_relations / max_relations * 0.8 + 0.1, 1.0);
511               
512                yieldEvent.WaitOne();               //wait until queue is not empty
513                if (userStopped)
514                    return;
515
516                while (yieldqueue.Count != 0)       //get all the results from the helper threads, and store them
517                {
518                    IntPtr yield = (IntPtr)yieldqueue.Dequeue();                   
519
520                    if (usePeer2Peer)
521                    {
522                        byte[] serializedYield = (byte[])serializeYield.Invoke(null, new object[] { yield });
523                        peerToPeer.Put(serializedYield);
524                    }
525
526                    saveYield.Invoke(null, new object[] { conf, yield });
527                }
528
529                if (usePeer2Peer)
530                {
531                    Queue dhtqueue = peerToPeer.GetLoadedYieldsQueue();
532                    while (dhtqueue.Count != 0)       //get all the loaded results from the DHT, and store them
533                    {
534                        byte[] yield = (byte[])dhtqueue.Dequeue();
535                        IntPtr deserializedYield = (IntPtr)deserializeYield.Invoke(null, new object[] { yield });
536                        saveYield.Invoke(null, new object[] { conf, deserializedYield });
537                    }
538                }
539
540                num_relations = (int)getNumRelations.Invoke(null, new object[] { conf });
541                showProgressPresentation(max_relations, num_relations, start_relations, start_sieving_time);
542
543                if (usePeer2Peer && !peerToPeer.SyncFactorManager(factorManager))   //another peer already finished sieving
544                {
545                    throw new AlreadySievedException();
546                }
547            }           
548        }
549
550        private void showProgressPresentation(int max_relations, int num_relations, int start_relations, DateTime start_sieving_time)
551        {
552            String logging_message = "Found " + num_relations + " of " + max_relations + " relations!";
553            double msleft = 0;
554
555            //calculate global performance in relations per ms:
556            double globalPerformance = 0;
557            foreach (double r in relationsPerMS)
558                globalPerformance += r;
559            if (usePeer2Peer)
560                globalPerformance += peerToPeer.GetP2PPerformance();
561
562            //Calculate the total time assuming that we can sieve 1 minute with the same performance:
563            double relationsCalculatableIn1Minute = 1000 * 60 * 1 * globalPerformance;
564            if (relationsCalculatableIn1Minute <= max_relations)
565            {
566                double p = ApproximatedPolynom(relationsCalculatableIn1Minute / max_relations);
567                double estimatedTotalTime = 1000 * 60 * 1 / p;
568
569                //Calculate the elapsed time assuming that we sieved with the same performance the whole time:
570                p = ApproximatedPolynom((double)num_relations / max_relations);
571                double estimatedElapsedTime = estimatedTotalTime * p;
572
573                //Calculate time left:
574                msleft = estimatedTotalTime - estimatedElapsedTime;
575                /*GuiLogMessage("Total: " + new TimeSpan(0, 0, 0, 0, (int)estimatedTotalTime), NotificationLevel.Info);
576                GuiLogMessage("Elapsed: " + new TimeSpan(0, 0, 0, 0, (int)estimatedElapsedTime), NotificationLevel.Info);*/
577            }           
578           
579            String timeLeft_message = "very soon";
580            String endtime_message = "very soon";
581            if (msleft > 0 && !double.IsInfinity(msleft))
582            {
583                TimeSpan ts = new TimeSpan(0, 0, 0, 0, (int)msleft);
584                timeLeft_message = showTimeSpan(ts) + " left";
585                endtime_message = "" + DateTime.Now.AddMilliseconds((long)msleft);
586            }
587
588            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
589            {
590                quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
591                quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
592                quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
593            }, null);
594
595            if (useGnuplot)
596            {
597                double percentage = (double)num_relations / max_relations;
598                double time = (DateTime.Now - start_sieving_time).TotalSeconds;
599                gnuplotFile.WriteLine("" + time + "\t\t" + percentage);
600            }
601        }
602
603        private static double ApproximatedPolynom(double x)
604        {
605            double a = -3.55504;
606            double b = 8.62296;
607            double c = -7.75103;
608            double d = 3.65871;
609            double progress = a * x * x * x * x + b * x * x * x + c * x * x + d * x;
610            return progress;
611        }
612
613        /// <summary>
614        /// This callback method is called by msieve. "list" is the trivial factor list (i.e. it consists of the factors that have been found without
615        /// using the quadratic sieve algorithm).
616        /// The method then factors all the factors that are still composite by using the quadratic sieve.
617        /// </summary>
618        private void getTrivialFactorlist(IntPtr list, IntPtr obj)
619        {
620            //add the trivial factors to the factor list:
621            factorManager.AddFactors(list);
622
623            if (usePeer2Peer)
624                peerToPeer.SyncFactorManager(factorManager);
625           
626            MethodInfo msieve_run_core = msieve.GetMethod("msieve_run_core");
627
628            //Now factorize as often as needed:
629            while (!factorManager.OnlyPrimes())
630            {
631                //get one composite factor, which we want to sieve now:
632                BigInteger compositeFactor = factorManager.GetCompositeFactor();
633                showFactorInformations(compositeFactor);
634                if (usePeer2Peer)
635                    peerToPeer.SetFactor(compositeFactor);
636
637                try
638                {
639                    //now start quadratic sieve on it:               
640                    IntPtr resultList = (IntPtr)msieve_run_core.Invoke(null, new object[2] { obj, compositeFactor.ToString() });
641                    if (userStopped)
642                        return;
643
644                    factorManager.ReplaceCompositeByFactors(compositeFactor, resultList);   //add the result list to factorManager
645
646                    if (usePeer2Peer)
647                        peerToPeer.SyncFactorManager(factorManager);
648                }
649                catch (AlreadySievedException)
650                {
651                    GuiLogMessage("Another peer already finished factorization of composite factor" + compositeFactor + ". Sieving next one...", NotificationLevel.Info);
652                }
653            }
654        }
655
656        private void showFactorInformations(BigInteger compositeFactor)
657        {
658            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
659            {
660                String compRep;
661                if (compositeFactor.ToString().Length < 6)
662                    compRep = compositeFactor.ToString();
663                else
664                    compRep = compositeFactor.ToString().Substring(0, 4) + "...";
665                quadraticSieveQuickWatchPresentation.factorInfo.Content = "Now sieving first composite factor! (" + compRep + ")";
666            }, null);
667        }
668
669        /// <summary>
670        /// Helper Thread for msieve, which sieves for relations:
671        /// </summary>
672        /// <param name="param">params</param>
673        private void MSieveJob(object param)
674        {
675            threadcount++;
676            object[] parameters = (object[])param;
677            IntPtr clone = (IntPtr)parameters[0];
678            int update = (int)parameters[1];
679            IntPtr core_sieve_fcn = (IntPtr)parameters[2];
680            Queue yieldqueue = (Queue)parameters[3];
681            int threadNR = (int)parameters[4];
682
683            try
684            {
685                MethodInfo collectRelations = msieve.GetMethod("collectRelations");
686                MethodInfo getYield = msieve.GetMethod("getYield");
687                MethodInfo getAmountOfRelationsInYield = msieve.GetMethod("getAmountOfRelationsInYield");
688
689                Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
690
691                while (running)
692                {
693                    try
694                    {
695                        //Calculate the performance of this thread:
696                        DateTime beginning = DateTime.Now;
697                        collectRelations.Invoke(null, new object[] { clone, update, core_sieve_fcn });
698                        IntPtr yield = (IntPtr)getYield.Invoke(null, new object[] { clone });
699
700                        int amountOfFullRelations = (int)getAmountOfRelationsInYield.Invoke(null, new object[] { yield });
701                        relationsPerMS[threadNR] = amountOfFullRelations / (DateTime.Now - beginning).TotalMilliseconds;
702
703                        if (usePeer2Peer)
704                            peerToPeer.SetOurPerformance(relationsPerMS);
705
706                        yieldqueue.Enqueue(yield);
707                        yieldEvent.Set();
708                    }
709                    catch (Exception ex)
710                    {
711                        GuiLogMessage("Error using msieve." + ex.Message, NotificationLevel.Error);
712                        threadcount = 0;
713                        return;
714                    }
715                }
716
717                conf_listMutex.WaitOne();
718                if (conf_list != null)
719                    conf_list[threadNR] = null;
720                MethodInfo freeSieveConf = msieve.GetMethod("freeSieveConf");
721                freeSieveConf.Invoke(null, new object[] { clone });
722                conf_listMutex.ReleaseMutex();
723            }
724            finally
725            {
726                threadcount--;
727            }
728        }       
729
730        /// <summary>
731        /// Stop all running threads
732        /// </summary>
733        private void stopThreads()
734        {
735            if (conf_list != null)
736            {
737                running = false;
738                if (usePeer2Peer)
739                    peerToPeer.StopLoadStoreThread();
740
741                MethodInfo stop = msieve.GetMethod("stop");
742                MethodInfo getObjFromConf = msieve.GetMethod("getObjFromConf");
743
744                conf_listMutex.WaitOne();
745                foreach (IntPtr conf in conf_list)
746                    if (conf != null)
747                        stop.Invoke(null, new object[] { getObjFromConf.Invoke(null, new object[] { conf }) });
748
749                conf_list = null;
750                conf_listMutex.ReleaseMutex();
751
752                GuiLogMessage("Waiting for threads to stop!", NotificationLevel.Debug);
753                while (threadcount > 0)
754                {
755                    Thread.Sleep(0);
756                }
757                GuiLogMessage("Threads stopped!", NotificationLevel.Debug);
758            }
759        }   
760
761        /// <summary>
762        /// Change the progress of this plugin
763        /// </summary>
764        /// <param name="value">value</param>
765        /// <param name="max">max</param>
766        private void ProgressChanged(double value, double max)
767        {
768            EventsHelper.ProgressChanged(OnPluginProgressChanged, this, new PluginProgressEventArgs(value, max));
769        }
770
771        private void FactorsChanged(List<BigInteger> primeFactors, List<BigInteger> compositeFactors)
772        {
773            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
774            {
775                quadraticSieveQuickWatchPresentation.factorList.Items.Clear();
776
777                foreach (BigInteger pf in primeFactors)         
778                    quadraticSieveQuickWatchPresentation.factorList.Items.Add("Prime Factor: " + pf.ToString());           
779
780                foreach (BigInteger cf in compositeFactors)
781                    quadraticSieveQuickWatchPresentation.factorList.Items.Add("Composite Factor: " + cf.ToString());
782            }, null);
783        }
784
785        /// <summary>
786        /// Logs a message to the CrypTool gui
787        /// </summary>
788        /// <param name="p">p</param>
789        /// <param name="notificationLevel">notificationLevel</param>
790        private void GuiLogMessage(string p, NotificationLevel notificationLevel)
791        {
792            EventsHelper.GuiLogMessage(OnGuiLogNotificationOccured, this, new GuiLogEventArgs(p, this, notificationLevel));
793        }
794
795        /// <summary>
796        /// Getter / Setter for the QuickWatchPresentation
797        /// </summary>
798        private QuadraticSievePresentation quadraticSieveQuickWatchPresentation
799        {
800            get { return QuickWatchPresentation as QuadraticSievePresentation; }
801        }
802
803        /// <summary>
804        /// dynamically loads the msieve dll file and sets the callbacks
805        /// </summary>
806        private void initMsieveDLL()
807        {
808            //Load msieve.dll (if necessary):
809            if (msieve == null || msieveDLL == null)
810            {
811                string s = Directory.GetCurrentDirectory();
812                string dllname;
813                if (IntPtr.Size == 4)
814                    dllname = "msieve.dll";
815                else
816                    dllname = "msieve64.dll";
817
818                msieveDLL = Assembly.LoadFile(Directory.GetCurrentDirectory() + "\\AppReferences\\"  + dllname);
819                msieve = msieveDLL.GetType("Msieve.msieve");
820            }
821
822            //init msieve with callbacks:
823            MethodInfo initMsieve = msieve.GetMethod("initMsieve");
824            Object callback_struct = Activator.CreateInstance(msieveDLL.GetType("Msieve.callback_struct"));           
825            FieldInfo prepareSievingField = msieveDLL.GetType("Msieve.callback_struct").GetField("prepareSieving");
826            FieldInfo getTrivialFactorlistField = msieveDLL.GetType("Msieve.callback_struct").GetField("getTrivialFactorlist");           
827            Delegate prepareSievingDel = MulticastDelegate.CreateDelegate(msieveDLL.GetType("Msieve.prepareSievingDelegate"), this, "prepareSieving");
828            Delegate getTrivialFactorlistDel = MulticastDelegate.CreateDelegate(msieveDLL.GetType("Msieve.getTrivialFactorlistDelegate"), this, "getTrivialFactorlist");           
829            prepareSievingField.SetValue(callback_struct, prepareSievingDel);
830            getTrivialFactorlistField.SetValue(callback_struct, getTrivialFactorlistDel);
831            initMsieve.Invoke(null, new object[1] { callback_struct });
832        }
833
834        private void peerToPeer_P2PWarning(string warning)
835        {
836            GuiLogMessage(warning, NotificationLevel.Warning);
837        }
838
839        #endregion
840
841    }
842}
Note: See TracBrowser for help on using the repository browser.