diff --git a/Modules.Packed/OpenCLABC.pas b/Modules.Packed/OpenCLABC.pas index ef15f6a3..332fa1ab 100644 --- a/Modules.Packed/OpenCLABC.pas +++ b/Modules.Packed/OpenCLABC.pas @@ -707,9 +707,7 @@ NativeValueArea = record public static property ValueSize: integer read Marshal.SizeOf(default(T)); public property ByteSize: UIntPtr read new UIntPtr(ValueSize); - //TODO #???? - private function PointerUntyped := pointer(ptr); - public property Pointer: ^T read PointerUntyped(); + public property Pointer: ^T read ptr.ToPointer; public property Value: T read Pointer^ write Pointer^ := value; public property UntypedArea: NativeMemoryArea read new NativeMemoryArea(self.ptr, self.ByteSize); @@ -1075,9 +1073,8 @@ NativeArrayEnumerator = record(IEnumerator) {$region ICollection} - //TODO #???? - ///-- - public property {System.Collections.Generic.ICollection.}Count: integer read self.Length; + //TODO #3073 + public function System.Collections.Generic.ICollection.get_Count: integer := self.Length; public property System.Collections.Generic.ICollection.IsReadOnly: boolean read boolean(true); public procedure System.Collections.Generic.ICollection.Add(item: T) := raise new NotSupportedException; @@ -1131,8 +1128,7 @@ NativeArrayEnumerator = record(IEnumerator) if self.Length<>0 then begin sb += ' '; - //TODO #????: as - foreach var x in self as IList do + foreach var x in self do begin sb += _ObjectToString(x); sb += ', '; @@ -1291,12 +1287,6 @@ EventRetainReleaseData = record $'{time} | {GetActStr} when: {reason}'; end; - //TODO #2680 - /// - TimeNString = auto class - t: TimeSpan; - s: string; - end; /// EventUseLog = sealed class private log_lines := new List; @@ -1316,14 +1306,14 @@ EventRetainReleaseData = record ref_c -= 1; end; - private function MakeReports: sequence of array of TimeNString; + private function MakeReports: sequence of array of (TimeSpan,string); begin - var res := new List; + var res := new List<(TimeSpan,string)>; var c := 0; foreach var act in log_lines do begin c += if act.is_release then -1 else +1; - res += new TimeNString(act.time, $'{c,3} | {act}'); + res += (act.time, $'{c,3} | {act}'); if c=0 then begin yield res.ToArray; @@ -1363,14 +1353,14 @@ EventRetainReleaseData = record var newest_report := TimeSpan.Zero; foreach var (r,ev) in Logs.SelectMany(kvp-> kvp.Value.MakeReports.Tabulate(r->kvp.Key) - ).OrderBy(\(r,ev)->r[0].t) do + ).OrderBy(\(r,ev)->r[0][0]) do begin - if r[0].t>newest_report then + if r[0][0]>newest_report then otp.WriteLine; otp.WriteLine($'Logging state change of {ev}:'); - foreach var l in r do - otp.WriteLine(l.s); - newest_report := |newest_report, r[^1].t|.Max; + foreach var (t,s) in r do + otp.WriteLine(s); + newest_report := |newest_report, r[^1][0]|.Max; otp.WriteLine('-'*30); end; @@ -3443,8 +3433,7 @@ CLArrayProperties = class begin var c := {$ifdef ForceMaxDebug} - //TODO #????: Лишние () - LoadTestContext() ?? + LoadTestContext ?? {$endif ForceMaxDebug} MakeNewDefaultContext; // Extra checks, in case .Default was explicitly set while generating new context @@ -3813,7 +3802,7 @@ CLProgramLinkOptions = class(CLProgramOptions) ); end; - //TODO #2899 + //TODO #3074 private function GetPropValue2(prop_f: _GetPropValueFunc) := GetPropValue(prop_f); //TODO #634 @@ -3996,6 +3985,7 @@ CLProgramLinkOptions = class(CLProgramOptions) if Result=cl_program.Zero then //TODO В этом случае нельзя получить лог??? + // - Пока ещё молча обсуждаем: https://github.com/KhronosGroup/OpenCL-Docs/issues/1075 OpenCLABCInternalException.RaiseIfError(ec) else CheckBuildFail(Result, ec, clErrorCode.LINK_PROGRAM_FAILURE, @@ -4150,8 +4140,9 @@ CLProgramLinkOptions = class(CLProgramOptions) {$endregion Deserialize} - //TODO #2668 + //TODO #3075 public static function operator=(p1,p2: CLProgramCode) := p1.Equals(p2); + public static function operator<>(p1,p2: CLProgramCode) := not(p1=p2); end; @@ -6719,6 +6710,7 @@ CLMemoryUsage = record {$endif ErrHandlerDebug} //TODO Дать пользователю это решать + // - Вообще это надо ещё перепродумать исходя из реального случая, к примеру в моём мандельброте private static max_spin_wait := TimeSpan.FromMilliseconds(50); ///Ожидает окончания выполнения очереди (если оно ещё не завершилось) ///Кидает System.AggregateException, содержащие ошибки при выполнении очереди, если такие имеются @@ -8689,6 +8681,9 @@ function CQReleaseGL(params mem_objs: array of ICLMemory): CommandQueueNil; implementation +uses System.Collections; +uses System.Collections.Generic; + {$region Util type's} // To reorder first change OpenCLABC.Utils.drawio // Created using https://www.diagrams.net/ @@ -8809,8 +8804,7 @@ InterlockedBoolean = record end; -//TODO #???? -function ParameterQueue.NewSetter(val: T) := new ParameterQueueSetter(self as object as IParameterQueue, val); +function ParameterQueue.NewSetter(val: T) := new ParameterQueueSetter(self, val); type CLTaskParameterData = record @@ -9106,7 +9100,9 @@ function PreInvoke(self: ISimpleDelegateContainer; inp: TInp): TRes; p.Invoke(inp, nil); if typeof(TInp)<>typeof(TRes) then raise new OpenCLABCInternalException($'Proc inp [{TypeToTypeName(typeof(TInp))}] <> res [{TypeToTypeName(typeof(TRes))}]'); - Result := TRes(object(inp)); //TODO Убрать object. Пока не заменил as на TRes(...) - работало без него + //TODO Убрать object. Пока не заменил as на TRes(...) - работало без него + // - Это надо делать через что-то типа Utils\TypeMagic + Result := TRes(object(inp)); end; else raise new OpenCLABCInternalException($'Wrong DC type: [{TypeName(self)}] is not [{TypeToTypeName(typeof(TInp))}]=>[{TypeToTypeName(typeof(TRes))}]'); end; @@ -9241,14 +9237,12 @@ EventList = record Result := EventList.Empty; var count := 0; - //TODO #2589 - for var i := 0 to (evs as IList).Count-1 do + for var i := 0 to evs.Count-1 do count += evs.Item[i].count; if count=0 then exit; Result := new EventList(count); - //TODO #2589 - for var i := 0 to (evs as IList).Count-1 do + for var i := 0 to evs.Count-1 do Result += evs.Item[i]; end; @@ -9397,7 +9391,7 @@ EventList = record {$region DoubleList} type - DoubleList = sealed class + DoubleList = sealed class(IList) private items: array of T; private c1 := 0; {$ifdef DEBUG} @@ -9411,6 +9405,8 @@ EventList = record public property Capacity: integer read items.Length; + {$region DEBUG} + {$ifdef DEBUG} private procedure CheckFill(exp_done: boolean); begin @@ -9428,6 +9424,10 @@ EventList = record end; {$endif DEBUG} + {$endregion DEBUG} + + {$region Own operations} + public function L1Empty := c1=0; public procedure AddL1(item: T); @@ -9481,23 +9481,6 @@ EventList = record {$endif DEBUG} Result := new ArraySegment(items,items.Length-c2,c2); end; - //TODO Вместо выделения .ToArray, лучше бы реализовать IList... - // - Получится избежать пере-выделений при создании ErrHandlerBranchCombinator - public function GetAll: array of T; - begin - {$ifdef DEBUG} - CheckFill(true); - {$endif DEBUG} - var c := c1+c2; - Result := self.items; - if c=Result.Length then exit; - Result := new T[c]; - for var i := 0 to c1-1 do - Result[i] := items[i]; - var shift := c-items.Length; - for var i := items.Length-c2 to items.Length-1 do - Result[i+shift] := items[i]; - end; public function L1Any(pred: T->boolean): boolean; begin @@ -9514,6 +9497,87 @@ EventList = record function Combine(conv: ArraySegment->TRes) := ValueTuple.Create( conv(GetL1), conv(GetL2) ); + {$endregion Own operations} + + {$region interface's} + + {$region IList} + + private function GetListItem(_ind: integer): T; + begin + var ind := cardinal(_ind); + + if ind.Item[ind: integer]: T read GetListItem write raise new System.InvalidOperationException; + + function IList.IndexOf(item: T): integer; + begin + Result := 0; + raise new System.NotImplementedException; + end; + procedure IList.Insert(ind: integer; item: T) := + raise new System.InvalidOperationException; + procedure IList.RemoveAt(ind: integer) := + raise new System.InvalidOperationException; + + {$endregion IList} + + {$region ICollection} + + //TODO #3073 + function ICollection.get_Count: integer := c1+c2; + + //TODO #2779 + property ICollection.IsReadOnly: boolean read boolean(true); + + procedure ICollection.CopyTo(a: array of T; ind: integer); + begin + System.Array.Copy(self.items,0, a,ind, c1); + System.Array.Copy(self.items,self.items.Length-c2, a,ind+c1, c2); + end; + + function ICollection.Contains(item: T): boolean; + begin + Result := false; + raise new System.InvalidOperationException; + end; + procedure ICollection.Add(item: T) := + raise new System.InvalidOperationException; + function ICollection.Remove(item: T): boolean; + begin + Result := false; + raise new System.InvalidOperationException; + end; + procedure ICollection.Clear := + raise new System.InvalidOperationException; + + {$endregion ICollection} + + {$region IEnumerable} + + private function Enmr := GetL1 + GetL2; + function IEnumerable.GetEnumerator: IEnumerator := Enmr.GetEnumerator; + function IEnumerable.GetEnumerator: IEnumerator := Enmr.GetEnumerator; + + {$endregion IEnumerable} + + {$endregion interface's} + end; {$endregion DoubleList} @@ -9926,17 +9990,17 @@ LazyErrHandler = record end; private constructor := raise new OpenCLABCInternalException; - //TODO Принимать TList:IList? - public static function Wrap(origin: LazyErrHandler; branches: array of ErrHandler{$ifdef DEBUG}; stage_reason: string{$endif}): LazyErrHandler; + public static function Wrap(origin: LazyErrHandler; branches: TBranches{$ifdef DEBUG}; stage_reason: string{$endif}): LazyErrHandler; where TBranches: IList; begin Result := origin; - if branches.Length=0 then exit; + if branches.Count=0 then exit; var origin_v := origin.TrySkipFunc; Result := LazyErrHandler.FromValue( - if (branches.Length=1) and (origin_v=nil) then - branches.Single else + if (branches.Count=1) and (origin_v=nil) then + branches[0] else new ErrHandlerBranchCombinator( - origin_v, branches + //TODO #3076: & + origin_v, branches.ToArray& {$ifdef DEBUG}, stage_reason{$endif} ) ); @@ -10369,8 +10433,8 @@ function Invoke(self: ISimpleFunc0Container; insta_call_g: CLTaskGlo begin Result := done.TrySet(true); if not Result then exit; - // - Old INTEL drivers break if callback invoked by SetUserEventStatus deletes own event //TODO Delete this retain/release pair at some point + // - Old INTEL drivers break if callback invoked by SetUserEventStatus deletes own event OpenCLABCInternalException.RaiseIfError(cl.RetainEvent(uev)); try OpenCLABCInternalException.RaiseIfError( @@ -10392,18 +10456,6 @@ function Invoke(self: ISimpleFunc0Container; insta_call_g: CLTaskGlo public static function operator implicit(ev: UserEvent): cl_event := ev.uev; public static function operator implicit(ev: UserEvent): EventList := ev.uev; - //TODO #???? -// public static function operator+(ev1: EventList; ev2: UserEvent): EventList; -// begin -// Result := ev1 + ev2.uev; -// Result.abortable := true; -// end; -// public static procedure operator+=(ev1: EventList; ev2: UserEvent); -// begin -// ev1 += ev2.uev; -// ev1.abortable := true; -// end; - public function ToString: string; override := $'UserEvent[{uev.val}]'; {$endregion operator's} @@ -11498,7 +11550,6 @@ MultiuseableResultData = record protected procedure InitBeforeInvoke(g: CLTaskGlobalData; inited_mu: HashSet); override := exit; protected function InvokeToNil(g: CLTaskGlobalData; l: CLTaskLocalData): QueueResNil; override := new QueueResNil(l); - //TODO #????: Если убрать - ошибки компиляции нет, но сборка не загружается protected function InvokeToAny(g: CLTaskGlobalData; l: CLTaskLocalData): QueueRes ; override := qr_val_factory.MakeConst(l, self.Value); protected function InvokeToPtr(g: CLTaskGlobalData; l: CLTaskLocalData): QueueResPtr; override := qr_ptr_factory.MakeConst(l, self.Value); @@ -11513,17 +11564,14 @@ MultiuseableResultData = record protected procedure InitBeforeInvoke(g: CLTaskGlobalData; inited_mu: HashSet); override; begin - //TODO #???? - if g.parameters.ContainsKey(self as object as IParameterQueue) then exit; - //TODO #???? - g.parameters[self as object as IParameterQueue] := if self.DefaultDefined then + if g.parameters.ContainsKey(self) then exit; + g.parameters[self] := if self.DefaultDefined then new CLTaskParameterData(self.Default) else new CLTaskParameterData; end; private function GetParVal(g: CLTaskGlobalData) := - //TODO #???? - T(g.parameters[self as object as IParameterQueue].val); + T(g.parameters[self].val); protected function InvokeToNil(g: CLTaskGlobalData; l: CLTaskLocalData): QueueResNil; override := new QueueResNil(l); protected function InvokeToAny(g: CLTaskGlobalData; l: CLTaskLocalData): QueueRes ; override := qr_val_factory.MakeConst(l, self.GetParVal(g)); @@ -11689,9 +11737,8 @@ SimpleQueueArrayCommon = record g.ParallelInvoke(l, qs.Length+1, invoker-> begin for var i := 0 to qs.Length-1 do - //TODO #2610 - evs[i] := invoker.InvokeBranch&( - (g,l)->qs[i].InvokeToNil(g, l) + evs[i] := invoker.InvokeBranch( + qs[i].InvokeToNil ).AttachInvokeActions(g); var l_res := invoker.InvokeBranch(invoke_last); res := l_res; @@ -12210,7 +12257,7 @@ QueueArrayWorkUse = record(IQueueArrayWork) {$region Threaded} - //TODO #2657 + //TODO Cейчас парсер не принимает "(array of byte, word)->()" - #(2657) QueueResArr = array of QueueRes; CommandQueueThreadedArray = sealed class(CommandQueueArrayWithWork) @@ -15358,7 +15405,7 @@ function CommandQueue.ThenConvert(f: (T,CLContext)->TOtp; need_own_thre {$endif DEBUG} if should_insta_call then d.Invoke(g, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, g.c) else - //TODO #????: self. + //TODO #3078: self. Result.AddAction(c->self.d.Invoke(nil, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, c)); end; @@ -15421,8 +15468,7 @@ function CommandQueue.ThenConvert(f: (T,CLContext)->TOtp; need_own_thre prev_qr.ResEv, ()-> begin acts.Invoke(c); - //TODO #????: self. - self.d.Invoke(nil, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, c); + d.Invoke(nil, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, c); end, g {$ifdef EventDebug}, $'body of {TypeName(self)}'{$endif} ); @@ -17200,7 +17246,7 @@ function CommandQueue.HandleReplaceRes(handler: List -> T) := {$endif DEBUG} if should_insta_call then p.Invoke(g, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, g.c) else - //TODO #????: self. + //TODO #3078: self. Result.AddAction(c->self.p.Invoke(nil, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, c)); end; @@ -17397,8 +17443,7 @@ function AddCommand(cc: TContainer; comm: GPUCommand): TContai cc.TakeCommandsBack; Result := TContainer(cc.Clone); cc.commands_in := Result; - //TODO #???? - cc.old_command_count := (cc as GPUCommandContainer).commands.Count; + cc.old_command_count := cc.commands.Count; cc.commands := nil; Result.commands += comm; end; @@ -18652,77 +18697,6 @@ CLKernelArgPrivateCommon = record EnqueueableCore = static class - //TODO Положить после Invoke, потому что оно в таком порядке вызывается... - // - При поиске будет интуитивнее - private [MethodImpl(MethodImplOptions.AggressiveInlining)] - static function ExecuteEnqFunc( - prev_res: T; - cq: cl_command_queue; - ev_l2: EventList; - {$ifdef DEBUG}cancel_p: Action;{$endif} - enq_f: EnqFunc; - had_l1_err: boolean; - enq_err_handler: ErrHandler - {$ifdef DEBUG}; err_test_reason: string{$endif} - {$ifdef EventDebug}; q: object{$endif} - ): EnqRes; - begin - var direct_enq_res: DirectEnqRes; - try - {$ifdef DEBUG} - if prev_res=default(t) then - raise new OpenCLABCInternalException($'NULL Native'); - {$endif DEBUG} - Result := new EnqRes(ev_l2, nil); - if had_l1_err then - begin - {$ifdef DEBUG} - cancel_p; - {$endif DEBUG} - exit; - end; - - try - direct_enq_res := enq_f(prev_res, cq, ev_l2); - except - on e: Exception do - begin - enq_err_handler.AddErr(e{$ifdef DEBUG}, err_test_reason{$endif}); - exit; - end; - end; - finally - {$ifdef DEBUG} - enq_err_handler.EndMaybeError(err_test_reason); - {$endif DEBUG} - end; - - var (enq_ev, act) := direct_enq_res; - Result.Item2 := act; - - // NVidia implementation doesn't create event if ev_l2.HasError - if enq_ev=cl_event.Zero then - begin - if not ev_l2.HasError then - raise new OpenCLABCInternalException($''); - exit; - end; - // Optimize the same way for the rest of implementations - // Also makes sure the debug event count is the same for all vendors - if EventList.HasError(enq_ev) or ev_l2.HasError then - begin - cl.ReleaseEvent(enq_ev).RaiseIfError; - exit; - end; - - {$ifdef EventDebug} - EventDebug.RegisterEventRetain(enq_ev, $'Enq by {TypeName(q)}, waiting on: {ev_l2.evs?.JoinToString}'); - {$endif EventDebug} - // 1. ev_l2 can only be released after executing dependant command - // 2. If event in ev_l2 would complete with error, enq_ev would have non-descriptive error code - Result.Item1 := ev_l2 + enq_ev; - end; - public [MethodImpl(MethodImplOptions.AggressiveInlining)] static function Invoke( enq_c: integer; @@ -18793,7 +18767,7 @@ CLKernelArgPrivateCommon = record {$ifdef DEBUG}par_err_handlers.FakeAdd(false){$endif} else par_err_handlers.AddL2(enq_err_handler); - //TODO #2976 + //TODO #3079 var (ev_l1, ev_l2) := enq_evs.Combine(EventList.Combine&>); // When need_async_inv, cq needs to be secured for thread safety @@ -18811,7 +18785,7 @@ CLKernelArgPrivateCommon = record g.curr_err_handler := ErrHandlerBranchCombinator.Wrap( - LazyErrHandler.InvalidFunc, par_err_handlers.GetAll + LazyErrHandler.InvalidFunc, par_err_handlers {$ifdef DEBUG}, $'{TypeName(q)} origin+par+enq union'{$endif} ); var final_err_handler := g.curr_err_handler.TrySkipFunc; @@ -18858,6 +18832,75 @@ CLKernelArgPrivateCommon = record end; + private [MethodImpl(MethodImplOptions.AggressiveInlining)] + static function ExecuteEnqFunc( + prev_res: T; + cq: cl_command_queue; + ev_l2: EventList; + {$ifdef DEBUG}cancel_p: Action;{$endif} + enq_f: EnqFunc; + had_l1_err: boolean; + enq_err_handler: ErrHandler + {$ifdef DEBUG}; err_test_reason: string{$endif} + {$ifdef EventDebug}; q: object{$endif} + ): EnqRes; + begin + var direct_enq_res: DirectEnqRes; + try + {$ifdef DEBUG} + if prev_res=default(t) then + raise new OpenCLABCInternalException($'NULL Native'); + {$endif DEBUG} + Result := new EnqRes(ev_l2, nil); + if had_l1_err then + begin + {$ifdef DEBUG} + cancel_p; + {$endif DEBUG} + exit; + end; + + try + direct_enq_res := enq_f(prev_res, cq, ev_l2); + except + on e: Exception do + begin + enq_err_handler.AddErr(e{$ifdef DEBUG}, err_test_reason{$endif}); + exit; + end; + end; + finally + {$ifdef DEBUG} + enq_err_handler.EndMaybeError(err_test_reason); + {$endif DEBUG} + end; + + var (enq_ev, act) := direct_enq_res; + Result.Item2 := act; + + // NVidia implementation doesn't create event if ev_l2.HasError + if enq_ev=cl_event.Zero then + begin + if not ev_l2.HasError then + raise new OpenCLABCInternalException($''); + exit; + end; + // Optimize the same way for the rest of implementations + // Also makes sure the debug event count is the same for all vendors + if EventList.HasError(enq_ev) or ev_l2.HasError then + begin + cl.ReleaseEvent(enq_ev).RaiseIfError; + exit; + end; + + {$ifdef EventDebug} + EventDebug.RegisterEventRetain(enq_ev, $'Enq by {TypeName(q)}, waiting on: {ev_l2.evs?.JoinToString}'); + {$endif EventDebug} + // 1. ev_l2 can only be released after executing dependant command + // 2. If event in ev_l2 would complete with error, enq_ev would have non-descriptive error code + Result.Item1 := ev_l2 + enq_ev; + end; + end; {$endregion Core} @@ -37528,9 +37571,9 @@ GLIteropApiBlock = record var prev_ev := l.AttachInvokeActions(g{$ifdef EventDebug}, l{$endif}); var res_ev: cl_event; InvokeImpl(api_block, g.GetCQ(false), ntv_mem_objs, prev_ev, res_ev); - //TODO Проверить и сделать всё релевантное из EnqueueableCore - // - В частности что если enq_ev=0 из за предыдущих ошибок? Может ли тут NV тоже отказываться давать ивент? - // - И сделать issue в OpenCL-Docs об этом, типа кто прав (или оба?) + //TODO Проверить и сделать всё релевантное из EnqueueableCore + // - В частности что если enq_ev=0 из за предыдущих ошибок? Может ли тут NV тоже отказываться давать ивент? + // - И сделать issue в OpenCL-Docs об этом, типа кто прав (или оба?) {$ifdef EventDebug} EventDebug.RegisterEventRetain(res_ev, $'Enq by {TypeName(self)}, waiting on: {prev_ev.evs?.Take(prev_ev.count).JoinToString}'); {$endif EventDebug} diff --git a/Modules/OpenCLABC.pas b/Modules/OpenCLABC.pas index c1ff03dd..84d9689c 100644 --- a/Modules/OpenCLABC.pas +++ b/Modules/OpenCLABC.pas @@ -630,9 +630,7 @@ NativeValueArea = record public static property ValueSize: integer read Marshal.SizeOf(default(T)); public property ByteSize: UIntPtr read new UIntPtr(ValueSize); - //TODO #???? - private function PointerUntyped := pointer(ptr); - public property Pointer: ^T read PointerUntyped(); + public property Pointer: ^T read ptr.ToPointer; public property Value: T read Pointer^ write Pointer^ := value; public property UntypedArea: NativeMemoryArea read new NativeMemoryArea(self.ptr, self.ByteSize); @@ -966,9 +964,8 @@ NativeArrayEnumerator = record(IEnumerator) {$region ICollection} - //TODO #???? - ///-- - public property {System.Collections.Generic.ICollection.}Count: integer read self.Length; + //TODO #3073 + public function System.Collections.Generic.ICollection.get_Count: integer := self.Length; public property System.Collections.Generic.ICollection.IsReadOnly: boolean read boolean(true); public procedure System.Collections.Generic.ICollection.Add(item: T) := raise new NotSupportedException; @@ -1012,8 +1009,7 @@ NativeArrayEnumerator = record(IEnumerator) if self.Length<>0 then begin sb += ' '; - //TODO #????: as - foreach var x in self as IList do + foreach var x in self do begin sb += _ObjectToString(x); sb += ', '; @@ -1170,12 +1166,6 @@ EventRetainReleaseData = record $'{time} | {GetActStr} when: {reason}'; end; - //TODO #2680 - /// - TimeNString = auto class - t: TimeSpan; - s: string; - end; /// EventUseLog = sealed class private log_lines := new List; @@ -1195,14 +1185,14 @@ EventRetainReleaseData = record ref_c -= 1; end; - private function MakeReports: sequence of array of TimeNString; + private function MakeReports: sequence of array of (TimeSpan,string); begin - var res := new List; + var res := new List<(TimeSpan,string)>; var c := 0; foreach var act in log_lines do begin c += if act.is_release then -1 else +1; - res += new TimeNString(act.time, $'{c,3} | {act}'); + res += (act.time, $'{c,3} | {act}'); if c=0 then begin yield res.ToArray; @@ -1242,14 +1232,14 @@ EventRetainReleaseData = record var newest_report := TimeSpan.Zero; foreach var (r,ev) in Logs.SelectMany(kvp-> kvp.Value.MakeReports.Tabulate(r->kvp.Key) - ).OrderBy(\(r,ev)->r[0].t) do + ).OrderBy(\(r,ev)->r[0][0]) do begin - if r[0].t>newest_report then + if r[0][0]>newest_report then otp.WriteLine; otp.WriteLine($'Logging state change of {ev}:'); - foreach var l in r do - otp.WriteLine(l.s); - newest_report := |newest_report, r[^1].t|.Max; + foreach var (t,s) in r do + otp.WriteLine(s); + newest_report := |newest_report, r[^1][0]|.Max; otp.WriteLine('-'*30); end; @@ -1595,8 +1585,7 @@ EventRetainReleaseData = record begin var c := {$ifdef ForceMaxDebug} - //TODO #????: Лишние () - LoadTestContext() ?? + LoadTestContext ?? {$endif ForceMaxDebug} MakeNewDefaultContext; // Extra checks, in case .Default was explicitly set while generating new context @@ -1965,7 +1954,7 @@ CLProgramLinkOptions = class(CLProgramOptions) ); end; - //TODO #2899 + //TODO #3074 private function GetPropValue2(prop_f: _GetPropValueFunc) := GetPropValue(prop_f); //TODO #634 @@ -2148,6 +2137,7 @@ CLProgramLinkOptions = class(CLProgramOptions) if Result=cl_program.Zero then //TODO В этом случае нельзя получить лог??? + // - Пока ещё молча обсуждаем: https://github.com/KhronosGroup/OpenCL-Docs/issues/1075 OpenCLABCInternalException.RaiseIfError(ec) else CheckBuildFail(Result, ec, clErrorCode.LINK_PROGRAM_FAILURE, @@ -2302,8 +2292,9 @@ CLProgramLinkOptions = class(CLProgramOptions) {$endregion Deserialize} - //TODO #2668 + //TODO #3075 public static function operator=(p1,p2: CLProgramCode) := p1.Equals(p2); + public static function operator<>(p1,p2: CLProgramCode) := not(p1=p2); end; @@ -3522,6 +3513,7 @@ CLMemoryUsage = record {$endif ErrHandlerDebug} //TODO Дать пользователю это решать + // - Вообще это надо ещё перепродумать исходя из реального случая, к примеру в моём мандельброте private static max_spin_wait := TimeSpan.FromMilliseconds(50); public procedure Wait; begin @@ -3755,6 +3747,9 @@ function CQReleaseGL(params mem_objs: array of ICLMemory): CommandQueueNil; implementation +uses System.Collections; +uses System.Collections.Generic; + {$region Util type's} // To reorder first change OpenCLABC.Utils.drawio // Created using https://www.diagrams.net/ @@ -3875,8 +3870,7 @@ InterlockedBoolean = record end; -//TODO #???? -function ParameterQueue.NewSetter(val: T) := new ParameterQueueSetter(self as object as IParameterQueue, val); +function ParameterQueue.NewSetter(val: T) := new ParameterQueueSetter(self, val); type CLTaskParameterData = record @@ -4172,7 +4166,9 @@ function PreInvoke(self: ISimpleDelegateContainer; inp: TInp): TRes; p.Invoke(inp, nil); if typeof(TInp)<>typeof(TRes) then raise new OpenCLABCInternalException($'Proc inp [{TypeToTypeName(typeof(TInp))}] <> res [{TypeToTypeName(typeof(TRes))}]'); - Result := TRes(object(inp)); //TODO Убрать object. Пока не заменил as на TRes(...) - работало без него + //TODO Убрать object. Пока не заменил as на TRes(...) - работало без него + // - Это надо делать через что-то типа Utils\TypeMagic + Result := TRes(object(inp)); end; else raise new OpenCLABCInternalException($'Wrong DC type: [{TypeName(self)}] is not [{TypeToTypeName(typeof(TInp))}]=>[{TypeToTypeName(typeof(TRes))}]'); end; @@ -4307,14 +4303,12 @@ EventList = record Result := EventList.Empty; var count := 0; - //TODO #2589 - for var i := 0 to (evs as IList).Count-1 do + for var i := 0 to evs.Count-1 do count += evs.Item[i].count; if count=0 then exit; Result := new EventList(count); - //TODO #2589 - for var i := 0 to (evs as IList).Count-1 do + for var i := 0 to evs.Count-1 do Result += evs.Item[i]; end; @@ -4463,7 +4457,7 @@ EventList = record {$region DoubleList} type - DoubleList = sealed class + DoubleList = sealed class(IList) private items: array of T; private c1 := 0; {$ifdef DEBUG} @@ -4477,6 +4471,8 @@ EventList = record public property Capacity: integer read items.Length; + {$region DEBUG} + {$ifdef DEBUG} private procedure CheckFill(exp_done: boolean); begin @@ -4494,6 +4490,10 @@ EventList = record end; {$endif DEBUG} + {$endregion DEBUG} + + {$region Own operations} + public function L1Empty := c1=0; public procedure AddL1(item: T); @@ -4547,23 +4547,6 @@ EventList = record {$endif DEBUG} Result := new ArraySegment(items,items.Length-c2,c2); end; - //TODO Вместо выделения .ToArray, лучше бы реализовать IList... - // - Получится избежать пере-выделений при создании ErrHandlerBranchCombinator - public function GetAll: array of T; - begin - {$ifdef DEBUG} - CheckFill(true); - {$endif DEBUG} - var c := c1+c2; - Result := self.items; - if c=Result.Length then exit; - Result := new T[c]; - for var i := 0 to c1-1 do - Result[i] := items[i]; - var shift := c-items.Length; - for var i := items.Length-c2 to items.Length-1 do - Result[i+shift] := items[i]; - end; public function L1Any(pred: T->boolean): boolean; begin @@ -4580,6 +4563,87 @@ EventList = record function Combine(conv: ArraySegment->TRes) := ValueTuple.Create( conv(GetL1), conv(GetL2) ); + {$endregion Own operations} + + {$region interface's} + + {$region IList} + + private function GetListItem(_ind: integer): T; + begin + var ind := cardinal(_ind); + + if ind.Item[ind: integer]: T read GetListItem write raise new System.InvalidOperationException; + + function IList.IndexOf(item: T): integer; + begin + Result := 0; + raise new System.NotImplementedException; + end; + procedure IList.Insert(ind: integer; item: T) := + raise new System.InvalidOperationException; + procedure IList.RemoveAt(ind: integer) := + raise new System.InvalidOperationException; + + {$endregion IList} + + {$region ICollection} + + //TODO #3073 + function ICollection.get_Count: integer := c1+c2; + + //TODO #2779 + property ICollection.IsReadOnly: boolean read boolean(true); + + procedure ICollection.CopyTo(a: array of T; ind: integer); + begin + System.Array.Copy(self.items,0, a,ind, c1); + System.Array.Copy(self.items,self.items.Length-c2, a,ind+c1, c2); + end; + + function ICollection.Contains(item: T): boolean; + begin + Result := false; + raise new System.InvalidOperationException; + end; + procedure ICollection.Add(item: T) := + raise new System.InvalidOperationException; + function ICollection.Remove(item: T): boolean; + begin + Result := false; + raise new System.InvalidOperationException; + end; + procedure ICollection.Clear := + raise new System.InvalidOperationException; + + {$endregion ICollection} + + {$region IEnumerable} + + private function Enmr := GetL1 + GetL2; + function IEnumerable.GetEnumerator: IEnumerator := Enmr.GetEnumerator; + function IEnumerable.GetEnumerator: IEnumerator := Enmr.GetEnumerator; + + {$endregion IEnumerable} + + {$endregion interface's} + end; {$endregion DoubleList} @@ -4992,17 +5056,17 @@ LazyErrHandler = record end; private constructor := raise new OpenCLABCInternalException; - //TODO Принимать TList:IList? - public static function Wrap(origin: LazyErrHandler; branches: array of ErrHandler{$ifdef DEBUG}; stage_reason: string{$endif}): LazyErrHandler; + public static function Wrap(origin: LazyErrHandler; branches: TBranches{$ifdef DEBUG}; stage_reason: string{$endif}): LazyErrHandler; where TBranches: IList; begin Result := origin; - if branches.Length=0 then exit; + if branches.Count=0 then exit; var origin_v := origin.TrySkipFunc; Result := LazyErrHandler.FromValue( - if (branches.Length=1) and (origin_v=nil) then - branches.Single else + if (branches.Count=1) and (origin_v=nil) then + branches[0] else new ErrHandlerBranchCombinator( - origin_v, branches + //TODO #3076: & + origin_v, branches.ToArray& {$ifdef DEBUG}, stage_reason{$endif} ) ); @@ -5435,8 +5499,8 @@ function Invoke(self: ISimpleFunc0Container; insta_call_g: CLTaskGlo begin Result := done.TrySet(true); if not Result then exit; - // - Old INTEL drivers break if callback invoked by SetUserEventStatus deletes own event //TODO Delete this retain/release pair at some point + // - Old INTEL drivers break if callback invoked by SetUserEventStatus deletes own event OpenCLABCInternalException.RaiseIfError(cl.RetainEvent(uev)); try OpenCLABCInternalException.RaiseIfError( @@ -5458,18 +5522,6 @@ function Invoke(self: ISimpleFunc0Container; insta_call_g: CLTaskGlo public static function operator implicit(ev: UserEvent): cl_event := ev.uev; public static function operator implicit(ev: UserEvent): EventList := ev.uev; - //TODO #???? -// public static function operator+(ev1: EventList; ev2: UserEvent): EventList; -// begin -// Result := ev1 + ev2.uev; -// Result.abortable := true; -// end; -// public static procedure operator+=(ev1: EventList; ev2: UserEvent); -// begin -// ev1 += ev2.uev; -// ev1.abortable := true; -// end; - public function ToString: string; override := $'UserEvent[{uev.val}]'; {$endregion operator's} @@ -6564,7 +6616,6 @@ MultiuseableResultData = record protected procedure InitBeforeInvoke(g: CLTaskGlobalData; inited_mu: HashSet); override := exit; protected function InvokeToNil(g: CLTaskGlobalData; l: CLTaskLocalData): QueueResNil; override := new QueueResNil(l); - //TODO #????: Если убрать - ошибки компиляции нет, но сборка не загружается protected function InvokeToAny(g: CLTaskGlobalData; l: CLTaskLocalData): QueueRes ; override := qr_val_factory.MakeConst(l, self.Value); protected function InvokeToPtr(g: CLTaskGlobalData; l: CLTaskLocalData): QueueResPtr; override := qr_ptr_factory.MakeConst(l, self.Value); @@ -6579,17 +6630,14 @@ MultiuseableResultData = record protected procedure InitBeforeInvoke(g: CLTaskGlobalData; inited_mu: HashSet); override; begin - //TODO #???? - if g.parameters.ContainsKey(self as object as IParameterQueue) then exit; - //TODO #???? - g.parameters[self as object as IParameterQueue] := if self.DefaultDefined then + if g.parameters.ContainsKey(self) then exit; + g.parameters[self] := if self.DefaultDefined then new CLTaskParameterData(self.Default) else new CLTaskParameterData; end; private function GetParVal(g: CLTaskGlobalData) := - //TODO #???? - T(g.parameters[self as object as IParameterQueue].val); + T(g.parameters[self].val); protected function InvokeToNil(g: CLTaskGlobalData; l: CLTaskLocalData): QueueResNil; override := new QueueResNil(l); protected function InvokeToAny(g: CLTaskGlobalData; l: CLTaskLocalData): QueueRes ; override := qr_val_factory.MakeConst(l, self.GetParVal(g)); @@ -6755,9 +6803,8 @@ SimpleQueueArrayCommon = record g.ParallelInvoke(l, qs.Length+1, invoker-> begin for var i := 0 to qs.Length-1 do - //TODO #2610 - evs[i] := invoker.InvokeBranch&( - (g,l)->qs[i].InvokeToNil(g, l) + evs[i] := invoker.InvokeBranch( + qs[i].InvokeToNil ).AttachInvokeActions(g); var l_res := invoker.InvokeBranch(invoke_last); res := l_res; @@ -7276,7 +7323,7 @@ QueueArrayWorkUse = record(IQueueArrayWork) {$region Threaded} - //TODO #2657 + //TODO Cейчас парсер не принимает "(array of byte, word)->()" - #(2657) QueueResArr = array of QueueRes; CommandQueueThreadedArray = sealed class(CommandQueueArrayWithWork) @@ -7681,7 +7728,7 @@ function CommandQueue.ThenConvert(f: (T,CLContext)->TOtp; need_own_thre {$endif DEBUG} if should_insta_call then d.Invoke(g, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, g.c) else - //TODO #????: self. + //TODO #3078: self. Result.AddAction(c->self.d.Invoke(nil, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, c)); end; @@ -7744,8 +7791,7 @@ function CommandQueue.ThenConvert(f: (T,CLContext)->TOtp; need_own_thre prev_qr.ResEv, ()-> begin acts.Invoke(c); - //TODO #????: self. - self.d.Invoke(nil, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, c); + d.Invoke(nil, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, c); end, g {$ifdef EventDebug}, $'body of {TypeName(self)}'{$endif} ); @@ -9523,7 +9569,7 @@ function CommandQueue.HandleReplaceRes(handler: List -> T) := {$endif DEBUG} if should_insta_call then p.Invoke(g, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, g.c) else - //TODO #????: self. + //TODO #3078: self. Result.AddAction(c->self.p.Invoke(nil, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, c)); end; @@ -9720,8 +9766,7 @@ function AddCommand(cc: TContainer; comm: GPUCommand): TContai cc.TakeCommandsBack; Result := TContainer(cc.Clone); cc.commands_in := Result; - //TODO #???? - cc.old_command_count := (cc as GPUCommandContainer).commands.Count; + cc.old_command_count := cc.commands.Count; cc.commands := nil; Result.commands += comm; end; @@ -10083,77 +10128,6 @@ CLKernelArgPrivateCommon = record EnqueueableCore = static class - //TODO Положить после Invoke, потому что оно в таком порядке вызывается... - // - При поиске будет интуитивнее - private [MethodImpl(MethodImplOptions.AggressiveInlining)] - static function ExecuteEnqFunc( - prev_res: T; - cq: cl_command_queue; - ev_l2: EventList; - {$ifdef DEBUG}cancel_p: Action;{$endif} - enq_f: EnqFunc; - had_l1_err: boolean; - enq_err_handler: ErrHandler - {$ifdef DEBUG}; err_test_reason: string{$endif} - {$ifdef EventDebug}; q: object{$endif} - ): EnqRes; - begin - var direct_enq_res: DirectEnqRes; - try - {$ifdef DEBUG} - if prev_res=default(t) then - raise new OpenCLABCInternalException($'NULL Native'); - {$endif DEBUG} - Result := new EnqRes(ev_l2, nil); - if had_l1_err then - begin - {$ifdef DEBUG} - cancel_p; - {$endif DEBUG} - exit; - end; - - try - direct_enq_res := enq_f(prev_res, cq, ev_l2); - except - on e: Exception do - begin - enq_err_handler.AddErr(e{$ifdef DEBUG}, err_test_reason{$endif}); - exit; - end; - end; - finally - {$ifdef DEBUG} - enq_err_handler.EndMaybeError(err_test_reason); - {$endif DEBUG} - end; - - var (enq_ev, act) := direct_enq_res; - Result.Item2 := act; - - // NVidia implementation doesn't create event if ev_l2.HasError - if enq_ev=cl_event.Zero then - begin - if not ev_l2.HasError then - raise new OpenCLABCInternalException($''); - exit; - end; - // Optimize the same way for the rest of implementations - // Also makes sure the debug event count is the same for all vendors - if EventList.HasError(enq_ev) or ev_l2.HasError then - begin - cl.ReleaseEvent(enq_ev).RaiseIfError; - exit; - end; - - {$ifdef EventDebug} - EventDebug.RegisterEventRetain(enq_ev, $'Enq by {TypeName(q)}, waiting on: {ev_l2.evs?.JoinToString}'); - {$endif EventDebug} - // 1. ev_l2 can only be released after executing dependant command - // 2. If event in ev_l2 would complete with error, enq_ev would have non-descriptive error code - Result.Item1 := ev_l2 + enq_ev; - end; - public [MethodImpl(MethodImplOptions.AggressiveInlining)] static function Invoke( enq_c: integer; @@ -10224,7 +10198,7 @@ CLKernelArgPrivateCommon = record {$ifdef DEBUG}par_err_handlers.FakeAdd(false){$endif} else par_err_handlers.AddL2(enq_err_handler); - //TODO #2976 + //TODO #3079 var (ev_l1, ev_l2) := enq_evs.Combine(EventList.Combine&>); // When need_async_inv, cq needs to be secured for thread safety @@ -10242,7 +10216,7 @@ CLKernelArgPrivateCommon = record g.curr_err_handler := ErrHandlerBranchCombinator.Wrap( - LazyErrHandler.InvalidFunc, par_err_handlers.GetAll + LazyErrHandler.InvalidFunc, par_err_handlers {$ifdef DEBUG}, $'{TypeName(q)} origin+par+enq union'{$endif} ); var final_err_handler := g.curr_err_handler.TrySkipFunc; @@ -10289,6 +10263,75 @@ CLKernelArgPrivateCommon = record end; + private [MethodImpl(MethodImplOptions.AggressiveInlining)] + static function ExecuteEnqFunc( + prev_res: T; + cq: cl_command_queue; + ev_l2: EventList; + {$ifdef DEBUG}cancel_p: Action;{$endif} + enq_f: EnqFunc; + had_l1_err: boolean; + enq_err_handler: ErrHandler + {$ifdef DEBUG}; err_test_reason: string{$endif} + {$ifdef EventDebug}; q: object{$endif} + ): EnqRes; + begin + var direct_enq_res: DirectEnqRes; + try + {$ifdef DEBUG} + if prev_res=default(t) then + raise new OpenCLABCInternalException($'NULL Native'); + {$endif DEBUG} + Result := new EnqRes(ev_l2, nil); + if had_l1_err then + begin + {$ifdef DEBUG} + cancel_p; + {$endif DEBUG} + exit; + end; + + try + direct_enq_res := enq_f(prev_res, cq, ev_l2); + except + on e: Exception do + begin + enq_err_handler.AddErr(e{$ifdef DEBUG}, err_test_reason{$endif}); + exit; + end; + end; + finally + {$ifdef DEBUG} + enq_err_handler.EndMaybeError(err_test_reason); + {$endif DEBUG} + end; + + var (enq_ev, act) := direct_enq_res; + Result.Item2 := act; + + // NVidia implementation doesn't create event if ev_l2.HasError + if enq_ev=cl_event.Zero then + begin + if not ev_l2.HasError then + raise new OpenCLABCInternalException($''); + exit; + end; + // Optimize the same way for the rest of implementations + // Also makes sure the debug event count is the same for all vendors + if EventList.HasError(enq_ev) or ev_l2.HasError then + begin + cl.ReleaseEvent(enq_ev).RaiseIfError; + exit; + end; + + {$ifdef EventDebug} + EventDebug.RegisterEventRetain(enq_ev, $'Enq by {TypeName(q)}, waiting on: {ev_l2.evs?.JoinToString}'); + {$endif EventDebug} + // 1. ev_l2 can only be released after executing dependant command + // 2. If event in ev_l2 would complete with error, enq_ev would have non-descriptive error code + Result.Item1 := ev_l2 + enq_ev; + end; + end; {$endregion Core} @@ -11002,9 +11045,9 @@ GLIteropApiBlock = record var prev_ev := l.AttachInvokeActions(g{$ifdef EventDebug}, l{$endif}); var res_ev: cl_event; InvokeImpl(api_block, g.GetCQ(false), ntv_mem_objs, prev_ev, res_ev); - //TODO Проверить и сделать всё релевантное из EnqueueableCore - // - В частности что если enq_ev=0 из за предыдущих ошибок? Может ли тут NV тоже отказываться давать ивент? - // - И сделать issue в OpenCL-Docs об этом, типа кто прав (или оба?) + //TODO Проверить и сделать всё релевантное из EnqueueableCore + // - В частности что если enq_ev=0 из за предыдущих ошибок? Может ли тут NV тоже отказываться давать ивент? + // - И сделать issue в OpenCL-Docs об этом, типа кто прав (или оба?) {$ifdef EventDebug} EventDebug.RegisterEventRetain(res_ev, $'Enq by {TypeName(self)}, waiting on: {prev_ev.evs?.Take(prev_ev.count).JoinToString}'); {$endif EventDebug} diff --git a/Packing/Descriptions/OpenCLABC.predoc b/Packing/Descriptions/OpenCLABC.predoc index 2b905936..826c1e7c 100644 --- a/Packing/Descriptions/OpenCLABC.predoc +++ b/Packing/Descriptions/OpenCLABC.predoc @@ -640,9 +640,7 @@ type public static property ValueSize: integer read Marshal.SizeOf(default(T)); public property ByteSize: UIntPtr read new UIntPtr(ValueSize); - //TODO #???? - private function PointerUntyped := pointer(ptr); - public property Pointer: ^T read PointerUntyped(); + public property Pointer: ^T read ptr.ToPointer; public property Value: T read Pointer^ write Pointer^ := value; public property UntypedArea: NativeMemoryArea read new NativeMemoryArea(self.ptr, self.ByteSize); @@ -976,9 +974,8 @@ type {$region ICollection} - //TODO #???? - ///-- - public property {System.Collections.Generic.ICollection.}Count: integer read self.Length; + //TODO #3073 + public function System.Collections.Generic.ICollection.get_Count: integer := self.Length; public property System.Collections.Generic.ICollection.IsReadOnly: boolean read boolean(true); public procedure System.Collections.Generic.ICollection.Add(item: T) := raise new NotSupportedException; @@ -1022,8 +1019,7 @@ type if self.Length<>0 then begin sb += ' '; - //TODO #????: as - foreach var x in self as IList do + foreach var x in self do begin sb += _ObjectToString(x); sb += ', '; @@ -1180,12 +1176,6 @@ type $'{time} | {GetActStr} when: {reason}'; end; - //TODO #2680 - /// - TimeNString = auto class - t: TimeSpan; - s: string; - end; /// EventUseLog = sealed class private log_lines := new List; @@ -1205,14 +1195,14 @@ type ref_c -= 1; end; - private function MakeReports: sequence of array of TimeNString; + private function MakeReports: sequence of array of (TimeSpan,string); begin - var res := new List; + var res := new List<(TimeSpan,string)>; var c := 0; foreach var act in log_lines do begin c += if act.is_release then -1 else +1; - res += new TimeNString(act.time, $'{c,3} | {act}'); + res += (act.time, $'{c,3} | {act}'); if c=0 then begin yield res.ToArray; @@ -1252,14 +1242,14 @@ type var newest_report := TimeSpan.Zero; foreach var (r,ev) in Logs.SelectMany(kvp-> kvp.Value.MakeReports.Tabulate(r->kvp.Key) - ).OrderBy(\(r,ev)->r[0].t) do + ).OrderBy(\(r,ev)->r[0][0]) do begin - if r[0].t>newest_report then + if r[0][0]>newest_report then otp.WriteLine; otp.WriteLine($'Logging state change of {ev}:'); - foreach var l in r do - otp.WriteLine(l.s); - newest_report := |newest_report, r[^1].t|.Max; + foreach var (t,s) in r do + otp.WriteLine(s); + newest_report := |newest_report, r[^1][0]|.Max; otp.WriteLine('-'*30); end; @@ -3330,8 +3320,7 @@ type begin var c := {$ifdef ForceMaxDebug} - //TODO #????: Лишние () - LoadTestContext() ?? + LoadTestContext ?? {$endif ForceMaxDebug} MakeNewDefaultContext; // Extra checks, in case .Default was explicitly set while generating new context @@ -3700,7 +3689,7 @@ type ); end; - //TODO #2899 + //TODO #3074 private function GetPropValue2(prop_f: _GetPropValueFunc) := GetPropValue(prop_f); //TODO #634 @@ -3883,6 +3872,7 @@ type if Result=cl_program.Zero then //TODO В этом случае нельзя получить лог??? + // - Пока ещё молча обсуждаем: https://github.com/KhronosGroup/OpenCL-Docs/issues/1075 OpenCLABCInternalException.RaiseIfError(ec) else CheckBuildFail(Result, ec, clErrorCode.LINK_PROGRAM_FAILURE, @@ -4037,8 +4027,9 @@ type {$endregion Deserialize} - //TODO #2668 + //TODO #3075 public static function operator=(p1,p2: CLProgramCode) := p1.Equals(p2); + public static function operator<>(p1,p2: CLProgramCode) := not(p1=p2); end; @@ -6049,6 +6040,7 @@ type {$endif ErrHandlerDebug} //TODO Дать пользователю это решать + // - Вообще это надо ещё перепродумать исходя из реального случая, к примеру в моём мандельброте private static max_spin_wait := TimeSpan.FromMilliseconds(50); public procedure Wait; begin @@ -7614,6 +7606,9 @@ function CQReleaseGL(params mem_objs: array of ICLMemory): CommandQueueNil; implementation +uses System.Collections; +uses System.Collections.Generic; + {$region Util type's} // To reorder first change OpenCLABC.Utils.drawio // Created using https://www.diagrams.net/ @@ -7734,8 +7729,7 @@ type end; -//TODO #???? -function ParameterQueue.NewSetter(val: T) := new ParameterQueueSetter(self as object as IParameterQueue, val); +function ParameterQueue.NewSetter(val: T) := new ParameterQueueSetter(self, val); type CLTaskParameterData = record @@ -8031,7 +8025,9 @@ begin p.Invoke(inp, nil); if typeof(TInp)<>typeof(TRes) then raise new OpenCLABCInternalException($'Proc inp [{TypeToTypeName(typeof(TInp))}] <> res [{TypeToTypeName(typeof(TRes))}]'); - Result := TRes(object(inp)); //TODO Убрать object. Пока не заменил as на TRes(...) - работало без него + //TODO Убрать object. Пока не заменил as на TRes(...) - работало без него + // - Это надо делать через что-то типа Utils\TypeMagic + Result := TRes(object(inp)); end; else raise new OpenCLABCInternalException($'Wrong DC type: [{TypeName(self)}] is not [{TypeToTypeName(typeof(TInp))}]=>[{TypeToTypeName(typeof(TRes))}]'); end; @@ -8166,14 +8162,12 @@ type Result := EventList.Empty; var count := 0; - //TODO #2589 - for var i := 0 to (evs as IList).Count-1 do + for var i := 0 to evs.Count-1 do count += evs.Item[i].count; if count=0 then exit; Result := new EventList(count); - //TODO #2589 - for var i := 0 to (evs as IList).Count-1 do + for var i := 0 to evs.Count-1 do Result += evs.Item[i]; end; @@ -8322,7 +8316,7 @@ type {$region DoubleList} type - DoubleList = sealed class + DoubleList = sealed class(IList) private items: array of T; private c1 := 0; {$ifdef DEBUG} @@ -8336,6 +8330,8 @@ type public property Capacity: integer read items.Length; + {$region DEBUG} + {$ifdef DEBUG} private procedure CheckFill(exp_done: boolean); begin @@ -8353,6 +8349,10 @@ type end; {$endif DEBUG} + {$endregion DEBUG} + + {$region Own operations} + public function L1Empty := c1=0; public procedure AddL1(item: T); @@ -8406,23 +8406,6 @@ type {$endif DEBUG} Result := new ArraySegment(items,items.Length-c2,c2); end; - //TODO Вместо выделения .ToArray, лучше бы реализовать IList... - // - Получится избежать пере-выделений при создании ErrHandlerBranchCombinator - public function GetAll: array of T; - begin - {$ifdef DEBUG} - CheckFill(true); - {$endif DEBUG} - var c := c1+c2; - Result := self.items; - if c=Result.Length then exit; - Result := new T[c]; - for var i := 0 to c1-1 do - Result[i] := items[i]; - var shift := c-items.Length; - for var i := items.Length-c2 to items.Length-1 do - Result[i+shift] := items[i]; - end; public function L1Any(pred: T->boolean): boolean; begin @@ -8439,6 +8422,87 @@ type function Combine(conv: ArraySegment->TRes) := ValueTuple.Create( conv(GetL1), conv(GetL2) ); + {$endregion Own operations} + + {$region interface's} + + {$region IList} + + private function GetListItem(_ind: integer): T; + begin + var ind := cardinal(_ind); + + if ind.Item[ind: integer]: T read GetListItem write raise new System.InvalidOperationException; + + function IList.IndexOf(item: T): integer; + begin + Result := 0; + raise new System.NotImplementedException; + end; + procedure IList.Insert(ind: integer; item: T) := + raise new System.InvalidOperationException; + procedure IList.RemoveAt(ind: integer) := + raise new System.InvalidOperationException; + + {$endregion IList} + + {$region ICollection} + + //TODO #3073 + function ICollection.get_Count: integer := c1+c2; + + //TODO #2779 + property ICollection.IsReadOnly: boolean read boolean(true); + + procedure ICollection.CopyTo(a: array of T; ind: integer); + begin + System.Array.Copy(self.items,0, a,ind, c1); + System.Array.Copy(self.items,self.items.Length-c2, a,ind+c1, c2); + end; + + function ICollection.Contains(item: T): boolean; + begin + Result := false; + raise new System.InvalidOperationException; + end; + procedure ICollection.Add(item: T) := + raise new System.InvalidOperationException; + function ICollection.Remove(item: T): boolean; + begin + Result := false; + raise new System.InvalidOperationException; + end; + procedure ICollection.Clear := + raise new System.InvalidOperationException; + + {$endregion ICollection} + + {$region IEnumerable} + + private function Enmr := GetL1 + GetL2; + function IEnumerable.GetEnumerator: IEnumerator := Enmr.GetEnumerator; + function IEnumerable.GetEnumerator: IEnumerator := Enmr.GetEnumerator; + + {$endregion IEnumerable} + + {$endregion interface's} + end; {$endregion DoubleList} @@ -8851,17 +8915,17 @@ type end; private constructor := raise new OpenCLABCInternalException; - //TODO Принимать TList:IList? - public static function Wrap(origin: LazyErrHandler; branches: array of ErrHandler{$ifdef DEBUG}; stage_reason: string{$endif}): LazyErrHandler; + public static function Wrap(origin: LazyErrHandler; branches: TBranches{$ifdef DEBUG}; stage_reason: string{$endif}): LazyErrHandler; where TBranches: IList; begin Result := origin; - if branches.Length=0 then exit; + if branches.Count=0 then exit; var origin_v := origin.TrySkipFunc; Result := LazyErrHandler.FromValue( - if (branches.Length=1) and (origin_v=nil) then - branches.Single else + if (branches.Count=1) and (origin_v=nil) then + branches[0] else new ErrHandlerBranchCombinator( - origin_v, branches + //TODO #3076: & + origin_v, branches.ToArray& {$ifdef DEBUG}, stage_reason{$endif} ) ); @@ -9294,8 +9358,8 @@ type begin Result := done.TrySet(true); if not Result then exit; - // - Old INTEL drivers break if callback invoked by SetUserEventStatus deletes own event //TODO Delete this retain/release pair at some point + // - Old INTEL drivers break if callback invoked by SetUserEventStatus deletes own event OpenCLABCInternalException.RaiseIfError(cl.RetainEvent(uev)); try OpenCLABCInternalException.RaiseIfError( @@ -9317,18 +9381,6 @@ type public static function operator implicit(ev: UserEvent): cl_event := ev.uev; public static function operator implicit(ev: UserEvent): EventList := ev.uev; - //TODO #???? -// public static function operator+(ev1: EventList; ev2: UserEvent): EventList; -// begin -// Result := ev1 + ev2.uev; -// Result.abortable := true; -// end; -// public static procedure operator+=(ev1: EventList; ev2: UserEvent); -// begin -// ev1 += ev2.uev; -// ev1.abortable := true; -// end; - public function ToString: string; override := $'UserEvent[{uev.val}]'; {$endregion operator's} @@ -10423,7 +10475,6 @@ type protected procedure InitBeforeInvoke(g: CLTaskGlobalData; inited_mu: HashSet); override := exit; protected function InvokeToNil(g: CLTaskGlobalData; l: CLTaskLocalData): QueueResNil; override := new QueueResNil(l); - //TODO #????: Если убрать - ошибки компиляции нет, но сборка не загружается protected function InvokeToAny(g: CLTaskGlobalData; l: CLTaskLocalData): QueueRes ; override := qr_val_factory.MakeConst(l, self.Value); protected function InvokeToPtr(g: CLTaskGlobalData; l: CLTaskLocalData): QueueResPtr; override := qr_ptr_factory.MakeConst(l, self.Value); @@ -10438,17 +10489,14 @@ type protected procedure InitBeforeInvoke(g: CLTaskGlobalData; inited_mu: HashSet); override; begin - //TODO #???? - if g.parameters.ContainsKey(self as object as IParameterQueue) then exit; - //TODO #???? - g.parameters[self as object as IParameterQueue] := if self.DefaultDefined then + if g.parameters.ContainsKey(self) then exit; + g.parameters[self] := if self.DefaultDefined then new CLTaskParameterData(self.Default) else new CLTaskParameterData; end; private function GetParVal(g: CLTaskGlobalData) := - //TODO #???? - T(g.parameters[self as object as IParameterQueue].val); + T(g.parameters[self].val); protected function InvokeToNil(g: CLTaskGlobalData; l: CLTaskLocalData): QueueResNil; override := new QueueResNil(l); protected function InvokeToAny(g: CLTaskGlobalData; l: CLTaskLocalData): QueueRes ; override := qr_val_factory.MakeConst(l, self.GetParVal(g)); @@ -10614,9 +10662,8 @@ type g.ParallelInvoke(l, qs.Length+1, invoker-> begin for var i := 0 to qs.Length-1 do - //TODO #2610 - evs[i] := invoker.InvokeBranch&( - (g,l)->qs[i].InvokeToNil(g, l) + evs[i] := invoker.InvokeBranch( + qs[i].InvokeToNil ).AttachInvokeActions(g); var l_res := invoker.InvokeBranch(invoke_last); res := l_res; @@ -11135,7 +11182,7 @@ function operator*(m1, m2: WaitMarker); extensionmethod := CommandQueueBase(m1) {$region Threaded} - //TODO #2657 + //TODO Cейчас парсер не принимает "(array of byte, word)->()" - #(2657) QueueResArr = array of QueueRes; CommandQueueThreadedArray = sealed class(CommandQueueArrayWithWork) @@ -14283,7 +14330,7 @@ type {$endif DEBUG} if should_insta_call then d.Invoke(g, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, g.c) else - //TODO #????: self. + //TODO #3078: self. Result.AddAction(c->self.d.Invoke(nil, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, c)); end; @@ -14346,8 +14393,7 @@ type prev_qr.ResEv, ()-> begin acts.Invoke(c); - //TODO #????: self. - self.d.Invoke(nil, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, c); + d.Invoke(nil, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, c); end, g {$ifdef EventDebug}, $'body of {TypeName(self)}'{$endif} ); @@ -16125,7 +16171,7 @@ type {$endif DEBUG} if should_insta_call then p.Invoke(g, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, g.c) else - //TODO #????: self. + //TODO #3078: self. Result.AddAction(c->self.p.Invoke(nil, err_handler{$ifdef DEBUG}, err_test_reason{$endif}, prev_qr.GetResDirect, c)); end; @@ -16322,8 +16368,7 @@ begin cc.TakeCommandsBack; Result := TContainer(cc.Clone); cc.commands_in := Result; - //TODO #???? - cc.old_command_count := (cc as GPUCommandContainer).commands.Count; + cc.old_command_count := cc.commands.Count; cc.commands := nil; Result.commands += comm; end; @@ -17577,77 +17622,6 @@ type EnqueueableCore = static class - //TODO Положить после Invoke, потому что оно в таком порядке вызывается... - // - При поиске будет интуитивнее - private [MethodImpl(MethodImplOptions.AggressiveInlining)] - static function ExecuteEnqFunc( - prev_res: T; - cq: cl_command_queue; - ev_l2: EventList; - {$ifdef DEBUG}cancel_p: Action;{$endif} - enq_f: EnqFunc; - had_l1_err: boolean; - enq_err_handler: ErrHandler - {$ifdef DEBUG}; err_test_reason: string{$endif} - {$ifdef EventDebug}; q: object{$endif} - ): EnqRes; - begin - var direct_enq_res: DirectEnqRes; - try - {$ifdef DEBUG} - if prev_res=default(t) then - raise new OpenCLABCInternalException($'NULL Native'); - {$endif DEBUG} - Result := new EnqRes(ev_l2, nil); - if had_l1_err then - begin - {$ifdef DEBUG} - cancel_p; - {$endif DEBUG} - exit; - end; - - try - direct_enq_res := enq_f(prev_res, cq, ev_l2); - except - on e: Exception do - begin - enq_err_handler.AddErr(e{$ifdef DEBUG}, err_test_reason{$endif}); - exit; - end; - end; - finally - {$ifdef DEBUG} - enq_err_handler.EndMaybeError(err_test_reason); - {$endif DEBUG} - end; - - var (enq_ev, act) := direct_enq_res; - Result.Item2 := act; - - // NVidia implementation doesn't create event if ev_l2.HasError - if enq_ev=cl_event.Zero then - begin - if not ev_l2.HasError then - raise new OpenCLABCInternalException($''); - exit; - end; - // Optimize the same way for the rest of implementations - // Also makes sure the debug event count is the same for all vendors - if EventList.HasError(enq_ev) or ev_l2.HasError then - begin - cl.ReleaseEvent(enq_ev).RaiseIfError; - exit; - end; - - {$ifdef EventDebug} - EventDebug.RegisterEventRetain(enq_ev, $'Enq by {TypeName(q)}, waiting on: {ev_l2.evs?.JoinToString}'); - {$endif EventDebug} - // 1. ev_l2 can only be released after executing dependant command - // 2. If event in ev_l2 would complete with error, enq_ev would have non-descriptive error code - Result.Item1 := ev_l2 + enq_ev; - end; - public [MethodImpl(MethodImplOptions.AggressiveInlining)] static function Invoke( enq_c: integer; @@ -17718,7 +17692,7 @@ type {$ifdef DEBUG}par_err_handlers.FakeAdd(false){$endif} else par_err_handlers.AddL2(enq_err_handler); - //TODO #2976 + //TODO #3079 var (ev_l1, ev_l2) := enq_evs.Combine(EventList.Combine&>); // When need_async_inv, cq needs to be secured for thread safety @@ -17736,7 +17710,7 @@ type g.curr_err_handler := ErrHandlerBranchCombinator.Wrap( - LazyErrHandler.InvalidFunc, par_err_handlers.GetAll + LazyErrHandler.InvalidFunc, par_err_handlers {$ifdef DEBUG}, $'{TypeName(q)} origin+par+enq union'{$endif} ); var final_err_handler := g.curr_err_handler.TrySkipFunc; @@ -17783,6 +17757,75 @@ type end; + private [MethodImpl(MethodImplOptions.AggressiveInlining)] + static function ExecuteEnqFunc( + prev_res: T; + cq: cl_command_queue; + ev_l2: EventList; + {$ifdef DEBUG}cancel_p: Action;{$endif} + enq_f: EnqFunc; + had_l1_err: boolean; + enq_err_handler: ErrHandler + {$ifdef DEBUG}; err_test_reason: string{$endif} + {$ifdef EventDebug}; q: object{$endif} + ): EnqRes; + begin + var direct_enq_res: DirectEnqRes; + try + {$ifdef DEBUG} + if prev_res=default(t) then + raise new OpenCLABCInternalException($'NULL Native'); + {$endif DEBUG} + Result := new EnqRes(ev_l2, nil); + if had_l1_err then + begin + {$ifdef DEBUG} + cancel_p; + {$endif DEBUG} + exit; + end; + + try + direct_enq_res := enq_f(prev_res, cq, ev_l2); + except + on e: Exception do + begin + enq_err_handler.AddErr(e{$ifdef DEBUG}, err_test_reason{$endif}); + exit; + end; + end; + finally + {$ifdef DEBUG} + enq_err_handler.EndMaybeError(err_test_reason); + {$endif DEBUG} + end; + + var (enq_ev, act) := direct_enq_res; + Result.Item2 := act; + + // NVidia implementation doesn't create event if ev_l2.HasError + if enq_ev=cl_event.Zero then + begin + if not ev_l2.HasError then + raise new OpenCLABCInternalException($''); + exit; + end; + // Optimize the same way for the rest of implementations + // Also makes sure the debug event count is the same for all vendors + if EventList.HasError(enq_ev) or ev_l2.HasError then + begin + cl.ReleaseEvent(enq_ev).RaiseIfError; + exit; + end; + + {$ifdef EventDebug} + EventDebug.RegisterEventRetain(enq_ev, $'Enq by {TypeName(q)}, waiting on: {ev_l2.evs?.JoinToString}'); + {$endif EventDebug} + // 1. ev_l2 can only be released after executing dependant command + // 2. If event in ev_l2 would complete with error, enq_ev would have non-descriptive error code + Result.Item1 := ev_l2 + enq_ev; + end; + end; {$endregion Core} @@ -36453,9 +36496,9 @@ end; var prev_ev := l.AttachInvokeActions(g{$ifdef EventDebug}, l{$endif}); var res_ev: cl_event; InvokeImpl(api_block, g.GetCQ(false), ntv_mem_objs, prev_ev, res_ev); - //TODO Проверить и сделать всё релевантное из EnqueueableCore - // - В частности что если enq_ev=0 из за предыдущих ошибок? Может ли тут NV тоже отказываться давать ивент? - // - И сделать issue в OpenCL-Docs об этом, типа кто прав (или оба?) + //TODO Проверить и сделать всё релевантное из EnqueueableCore + // - В частности что если enq_ev=0 из за предыдущих ошибок? Может ли тут NV тоже отказываться давать ивент? + // - И сделать issue в OpenCL-Docs об этом, типа кто прав (или оба?) {$ifdef EventDebug} EventDebug.RegisterEventRetain(res_ev, $'Enq by {TypeName(self)}, waiting on: {prev_ev.evs?.Take(prev_ev.count).JoinToString}'); {$endif EventDebug}